<!DOCTYPE html>
<html lang="en" dir="ltr">

<head prefix="og: http://ogp.me/ns#">
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Android 中 MessageQueue 的 nativePollOnce – Yang Blog</title>
    


  
  <script defer src="/js/fuse.min.94c78ad70b02749822921660cf4e9f0b3701bc0680c421afb784a78228de0275.js"></script>



<script src="/js/enquire.min.dfb99dee1e029d51d6cfb672d847929890b1585402de17f5ed092edd72a688b4.js"></script>

<script defer src="/js/lazysizes.min.31dd6a2d3a1ec0f78a8df007535cf23f03aeb5c70f026e6d6a19dac3b3acc340.js"></script>

<script defer src="/js/helper/getParents.min.1618c696be7c98933f9a92677f518b512a74e55bdbb976b09936b4182e93181b.js"></script>

<script defer src="/js/helper/fadeinout.min.93a331f96194789a542f33690bbe4f0c102c7e78ffc018217f5a1c33010bad91.js"></script>

<script defer src="/js/helper/closest.min.js"></script>
  
<script>
  "use strict";

  
  
  if (window.NodeList && !NodeList.prototype.forEach) {
    NodeList.prototype.forEach = Array.prototype.forEach;
  }

  
  if (!String.prototype.includes) {
    String.prototype.includes = function (search, start) {
      'use strict';

      if (search instanceof RegExp) {
        throw TypeError('first argument must not be a RegExp');
      }
      if (start === undefined) { start = 0; }
      return this.indexOf(search, start) !== -1;
    };
  }

  
  Document.prototype.append = Element.prototype.append = function append() {
    this.appendChild(_mutation(arguments));
  };
  function _mutation(nodes) {
    if (!nodes.length) {
      throw new Error('DOM Exception 8');
    } else if (nodes.length === 1) {
      return typeof nodes[0] === 'string' ? document.createTextNode(nodes[0]) : nodes[0];
    } else {
      var
      fragment = document.createDocumentFragment(),
      length = nodes.length,
      index = -1,
      node;

      while (++index < length) {
        node = nodes[index];

        fragment.appendChild(typeof node === 'string' ? document.createTextNode(node) : node);
      }

      return fragment;
    }
  }

  
  if (!String.prototype.startsWith) {
    String.prototype.startsWith = function (searchString, position) {
      position = position || 0;
      return this.indexOf(searchString, position) === position;
    };
  }
  


  document.addEventListener('DOMContentLoaded', function () {
    
    var navCollapseBtn = document.querySelector('.navbar__burger');
    navCollapseBtn ? navCollapseBtn.addEventListener('click', function (e) {
      var navCollapse = document.querySelector('.navbarm__collapse');

      if (navCollapse) {
        var dataOpen = navCollapse.getAttribute('data-open');

        if (dataOpen === 'true') {
          navCollapse.setAttribute('data-open', 'false');
          navCollapse.style.maxHeight = 0;
          navCollapseBtn.classList.remove('is-active');
        } else {
          navCollapse.setAttribute('data-open', 'true');
          navCollapse.style.maxHeight = navCollapse.scrollHeight + "px";
          navCollapseBtn.classList.add('is-active');
        }
      }
    }) : null;
    


    
    var summaryContainer = document.querySelector('.summary__container');
    var searchResult = document.querySelector('.search-result');
    var searchResultCloseBtn = document.querySelector('.search-result__close');
    searchResultCloseBtn ? searchResultCloseBtn.addEventListener('click', function (e) {
      searchResult.setAttribute('data-display', 'none');
      summaryContainer.setAttribute('data-display', 'block');
    }) : null;
    


    
    document.querySelectorAll('.tab') ? 
    document.querySelectorAll('.tab').forEach(function(elem, idx) {
      var containerId = elem.getAttribute('id');
      var containerElem = elem;
      var tabLinks = elem.querySelectorAll('.tab__link');
      var tabContents = elem.querySelectorAll('.tab__content');
      var ids = [];

      tabLinks && tabLinks.length > 0 ?
      tabLinks.forEach(function(link, index, self) {
        link.onclick = function(e) {
          for (var i = 0; i < self.length; i++) {
            if (index === parseInt(i, 10)) {
              if (!self[i].classList.contains('active')) {
                self[i].classList.add('active');
                tabContents[i].style.display = 'block';
              }
            } else {
              self[i].classList.remove('active');
              tabContents[i].style.display = 'none';
            }
          }
        }
      }) : null;
    }) : null;
    


    
    document.querySelectorAll('.codetab') ? 
    document.querySelectorAll('.codetab').forEach(function(elem, idx) {
      var containerId = elem.getAttribute('id');
      var containerElem = elem;
      var codetabLinks = elem.querySelectorAll('.codetab__link');
      var codetabContents = elem.querySelectorAll('.codetab__content');
      var ids = [];

      codetabLinks && codetabLinks.length > 0 ?
      codetabLinks.forEach(function(link, index, self) {
        link.onclick = function(e) {
          for (var i = 0; i < self.length; i++) {
            if (index === parseInt(i, 10)) {
              if (!self[i].classList.contains('active')) {
                self[i].classList.add('active');
                codetabContents[i].style.display = 'block';
              }
            } else {
              self[i].classList.remove('active');
              codetabContents[i].style.display = 'none';
            }
          }
        }
      }) : null;
    }) : null;
    


    
    var gttBtn = document.getElementById("gtt");
    gttBtn.style.display = "none";
    gttBtn.addEventListener('click', function () {
      if (window.document.documentMode) {
        document.documentElement.scrollTop = 0;
      } else {
        scrollToTop(250);
      }
    });

    function scrollToTop(scrollDuration) {
      var scrollStep = -window.scrollY / (scrollDuration / 15);
      var scrollInterval = setInterval(function () {
        if (window.scrollY != 0) {
          window.scrollBy(0, scrollStep);
        }
        else clearInterval(scrollInterval);
      }, 15);
    }

    var scrollFunction = function () {
      if (document.body.scrollTop > 250 || document.documentElement.scrollTop > 250) {
        gttBtn.style.display = "block";
      } else {
        gttBtn.style.display = "none";
      }
    }
    


    
    var expandBtn = document.querySelectorAll('.expand__button');

    for (let i = 0; i < expandBtn.length; i++) {
      expandBtn[i].addEventListener("click", function () {
        var content = this.nextElementSibling;
        if (content.style.maxHeight) {
          content.style.maxHeight = null;
          this.querySelector('svg').classList.add('expand-icon__right');
          this.querySelector('svg').classList.remove('expand-icon__down');
        } else {
          content.style.maxHeight = content.scrollHeight + "px";
          this.querySelector('svg').classList.remove('expand-icon__right');
          this.querySelector('svg').classList.add('expand-icon__down');
        }
      });
    }
    


    
    var lastScrollTop = window.pageYOffset || document.documentElement.scrollTop;
    var tocElem = document.querySelector('.toc');
    var tableOfContentsElem = tocElem ? tocElem.querySelector('#TableOfContents') : null;
    var toggleTocElem = document.getElementById('toggle-toc');
    var singleContentsElem = document.querySelector('.single__contents');
    var navbar = document.querySelector('.navbar');
    var tocFlexbox = document.querySelector('.toc__flexbox');
    var tocFlexboxOuter = document.querySelector('.toc__flexbox--outer');
    var expandContents = document.querySelectorAll('.expand__content');
    var boxContents = document.querySelectorAll('.box');
    var notAllowedTitleIds = null;

    
    var tocFolding = JSON.parse("false");
    
    var tocLevels = JSON.parse("[\"h2\",\"h3\",\"h4\",\"h5\",\"h6\"]");
    
    if (tocLevels) {
      tocLevels = tocLevels.toString();
    } else {
      tocLevels = "h1, h2, h3, h4, h5, h6";
    }

    
    singleContentsElem && singleContentsElem.querySelectorAll(".tab") ?
    singleContentsElem.querySelectorAll(".tab").forEach(function (elem) {
      elem.querySelectorAll(tocLevels).forEach(function (element) {
        notAllowedTitleIds = Array.isArray(notAllowedTitleIds) ?
          notAllowedTitleIds.concat(element.getAttribute('id')) :
          [element.getAttribute('id')];
      });
    }) : null;

    
    expandContents ? expandContents.forEach(function(elem) {
      elem.querySelectorAll(tocLevels).forEach(function (element) {
        notAllowedTitleIds = Array.isArray(notAllowedTitleIds) ?
          notAllowedTitleIds.concat(element.getAttribute('id')) :
          [element.getAttribute('id')];
      });
    }) : null;

    
    boxContents ? boxContents.forEach(function(elem) {
      elem.querySelectorAll(tocLevels).forEach(function (element) {
        notAllowedTitleIds = Array.isArray(notAllowedTitleIds) ?
          notAllowedTitleIds.concat(element.getAttribute('id')) :
          [element.getAttribute('id')];
      });
    }) : null;

    
    window.onscroll = function () {
      scrollFunction();
      
      var st = window.pageYOffset || document.documentElement.scrollTop;
      if (st > lastScrollTop) { 
        if (st < 250) {
          gttBtn.style.display = "none";
        } else {
          gttBtn.style.display = "block";
        }

        if (st < 45) {
          return null;
        }
        
        if (!navbar.classList.contains('navbar--hide')) {
          navbar.classList.add('navbar--hide');
        } else if (navbar.classList.contains('navbar--show')) {
          navbar.classList.remove('navbar--show');
        }

        if (singleContentsElem) {
          if (singleContentsElem.querySelectorAll(tocLevels).length > 0) {
            singleContentsElem.querySelectorAll(tocLevels).forEach(function (elem) {
              if (toggleTocElem && !toggleTocElem.checked) {
                return null;
              }

              if (notAllowedTitleIds && notAllowedTitleIds.includes(elem.getAttribute('id'))) {
                return null;
              }
              
              if (document.documentElement.scrollTop >= elem.offsetTop) {
                if (tableOfContentsElem) {
                  var id = elem.getAttribute('id');
                  tocElem.querySelectorAll('a').forEach(function (elem) {
                    elem.classList.remove('active');
                  });
                  tocElem.querySelector('a[href="#' + id + '"]') ?
                    tocElem.querySelector('a[href="#' + id + '"]').classList.add('active') : null;

                  if (false === tocFolding) {
                    
                  } else {
                    tableOfContentsElem.querySelectorAll('ul') ?
                      tableOfContentsElem.querySelectorAll('ul').forEach(function (rootUl) {
                        rootUl.querySelectorAll('li').forEach(function (liElem) {
                          liElem.querySelectorAll('ul').forEach(function (ulElem) {
                            ulElem.style.display = 'none';
                          });
                        });
                      }) : null;
                  }

                  var curElem = tableOfContentsElem.querySelector("[href='#" + id + "']");
                  if (curElem && curElem.nextElementSibling) {
                    curElem.nextElementSibling.style.display = 'block';
                  }
                  getParents(curElem, 'ul') ?
                    getParents(curElem, 'ul').forEach(function (elem) {
                      elem.style.display = 'block';
                    }) : null;
                }
              }
            });
          } else {
            if (tocFlexbox) {
              tocFlexbox.setAttribute('data-position', '');
              if (!tocFlexbox.classList.contains('hide')) {
                tocFlexbox.classList.add('hide');
              }
            }
            if (tocFlexboxOuter) {
              tocFlexboxOuter.setAttribute('data-position', '');
              if (!tocFlexboxOuter.classList.contains('hide')) {
                tocFlexboxOuter.classList.add('hide');
              }
            }
          }
        }
      } else { 
        if (st < 250) {
          gttBtn.style.display = "none";
        }

        if (navbar.classList.contains('navbar--hide')) {
          navbar.classList.remove('navbar--hide');
        } else if (!navbar.classList.contains('navbar--show')) {
          navbar.classList.add('navbar--show');
        }

        if (singleContentsElem) {
          if (singleContentsElem.querySelectorAll(tocLevels).length > 0) {
            singleContentsElem.querySelectorAll(tocLevels).forEach(function (elem) {
              if (toggleTocElem && !toggleTocElem.checked) {
                return null;
              }
              
              if (notAllowedTitleIds && notAllowedTitleIds.includes(elem.getAttribute('id'))) {
                return null;
              }

              if (document.documentElement.scrollTop >= elem.offsetTop) {
                if (tableOfContentsElem) {
                  var id = elem.getAttribute('id');
                  tocElem.querySelectorAll('a').forEach(function (elem) {
                    elem.classList.remove('active');
                  });
                  tocElem.querySelector('a[href="#' + id + '"]') ?
                    tocElem.querySelector('a[href="#' + id + '"]').classList.add('active') : null;

                  if (false === tocFolding) {
                    
                  } else {
                    tableOfContentsElem.querySelectorAll('ul') ?
                      tableOfContentsElem.querySelectorAll('ul').forEach(function (rootUl) {
                        rootUl.querySelectorAll('li').forEach(function (liElem) {
                          liElem.querySelectorAll('ul').forEach(function (ulElem) {
                            ulElem.style.display = 'none';
                          });
                        });
                      }) : null;
                  }

                  var curElem = tableOfContentsElem.querySelector("[href='#" + id + "']");
                  if (curElem && curElem.nextElementSibling) {
                    curElem.nextElementSibling.style.display = 'block';
                  }
                  getParents(curElem, 'ul') ?
                    getParents(curElem, 'ul').forEach(function (elem) {
                      elem.style.display = 'block';
                    }) : null;
                }
              }
            });
          } else {
            if (tocFlexbox && !tocFlexbox.classList.contains('hide')) {
              tocFlexbox.classList.add('hide');
            }
            if (tocFlexboxOuter && !tocFlexboxOuter.classList.contains('hide')) {
              tocFlexboxOuter.classList.add('hide');
            }
          }
          
        }

        if (tableOfContentsElem && document.documentElement.scrollTop < 250) {
          if (false === tocFolding) {

          } else {
            tableOfContentsElem.querySelector('ul') ?
              tableOfContentsElem.querySelector('ul').querySelectorAll('li').forEach(function (liElem) {
                liElem.querySelectorAll('ul').forEach(function (ulElem) {
                  ulElem.style.display = 'none';
                });
              }) : null;
          }
        }
      }
      lastScrollTop = st <= 0 ? 0 : st;
    };
  


  
    var localTheme = localStorage.getItem('theme');
    var rootEleme = document.getElementById('root');
    var selectThemeElem = document.querySelectorAll('.select-theme');
    var selectThemeItemElem = document.querySelectorAll('.select-theme__item');

    var setMetaColor = function(themeColor) {
      var metaMsapplicationTileColor = document.getElementsByName('msapplication-TileColor')[0];
      var metaThemeColor = document.getElementsByName('theme-color')[0];
      var metaMsapplicationNavbuttonColor = document.getElementsByName('msapplication-navbutton-color')[0];
      var metaAppleMobileWebAappStatusBarStyle = document.getElementsByName('apple-mobile-web-app-status-bar-style')[0];

      if (themeColor.includes('dark')) {
        metaMsapplicationTileColor.setAttribute('content', '#fcfcfa');
        metaThemeColor.setAttribute('content', '#403E41');
        metaMsapplicationNavbuttonColor.setAttribute('content', '#403E41');
        metaAppleMobileWebAappStatusBarStyle.setAttribute('content', '#403E41');
      } else if (themeColor.includes('light')) {
        metaMsapplicationTileColor.setAttribute('content', '#555');
        metaThemeColor.setAttribute('content', '#eee');
        metaMsapplicationNavbuttonColor.setAttribute('content', '#eee');
        metaAppleMobileWebAappStatusBarStyle.setAttribute('content', '#eee');
      } else if (themeColor.includes('hacker')) {
        metaMsapplicationTileColor.setAttribute('content', '#e3cd26');
        metaThemeColor.setAttribute('content', '#252526');
        metaMsapplicationNavbuttonColor.setAttribute('content', '#252526');
        metaAppleMobileWebAappStatusBarStyle.setAttribute('content', '#252526');
      } else if (themeColor.includes('solarized')) {
        metaMsapplicationTileColor.setAttribute('content', '#d3af86');
        metaThemeColor.setAttribute('content', '#51412c');
        metaMsapplicationNavbuttonColor.setAttribute('content', '#51412c');
        metaAppleMobileWebAappStatusBarStyle.setAttribute('content', '#51412c');
      } else if (themeColor.includes('kimbie')) {
        metaMsapplicationTileColor.setAttribute('content', '#586e75');
        metaThemeColor.setAttribute('content', '#eee8d5');
        metaMsapplicationNavbuttonColor.setAttribute('content', '#eee8d5');
        metaAppleMobileWebAappStatusBarStyle.setAttribute('content', '#eee8d5');
      } 
    }
    
    if (localTheme) {
      selectThemeItemElem ? 
      selectThemeItemElem.forEach(function (elem) {
        if (elem.text.trim() === localTheme) {
          elem.classList.add('is-active');
        } else {
          elem.classList.remove('is-active');
        }
      }) : null;

      setMetaColor(localTheme);
    } else {
      setMetaColor(rootEleme.className);
    }

    selectThemeItemElem ? 
    selectThemeItemElem.forEach(function (v, i) {
      v.addEventListener('click', function (e) {
        var selectedThemeVariant = e.target.text.trim();
        localStorage.setItem('theme', selectedThemeVariant);
        setMetaColor(selectedThemeVariant);

        rootEleme.removeAttribute('class');
        rootEleme.classList.add('theme__' + selectedThemeVariant);
        selectThemeElem.forEach(function(rootElem) {
          rootElem.querySelectorAll('a').forEach(function (elem) {
            if (elem.classList) {
              if (elem.text.trim() === selectedThemeVariant) {
                if (!elem.classList.contains('is-active')) {
                  elem.classList.add('is-active');
                }
              } else {
                if (elem.classList.contains('is-active')) {
                  elem.classList.remove('is-active');
                }
              }
            }
          });
        });

        if (window.mermaid) {
          if (selectedThemeVariant === "dark" || selectedThemeVariant === "hacker") {
            mermaid.initialize({ theme: 'dark' });
            location.reload();
          } else {
            mermaid.initialize({ theme: 'default' });
            location.reload();
          }
        }

        var utterances = document.getElementById('utterances');
        if (utterances) {
          utterances.querySelector('iframe').contentWindow.postMessage({
            type: 'set-theme',
            theme: selectedThemeVariant === "dark" || selectedThemeVariant === "hacker" ? 'photon-dark' : selectedThemeVariant === 'kimbie' ? 'github-dark-orange' : 'github-light',
          }, 'https://utteranc.es');
        }

        var twitterCards = document.querySelectorAll('.twitter-timeline');
        if (twitterCards) {
          window.postMessage({
            type: 'set-twitter-theme',
            theme: selectedThemeVariant === 'light' || selectedThemeVariant === 'solarized' ? 'light' : 'dark',
          });
        }
      });
    }) : null;
  


  
    
    var baseurl = JSON.parse("\"https://blog.jiyang.site/\"");
    
    var permalink = JSON.parse("\"https://blog.jiyang.site/posts/2019-10-19-android%E4%B8%ADmessagequeue%E7%9A%84nativepollonce/\"");
    
    var langprefix = JSON.parse("\"\"");
    var searchResults = null;
    var searchMenu = null;
    var searchText = null;
    
    
    var enableSearch = JSON.parse("true");
    
    var enableSearchHighlight = JSON.parse("true");
    
    var searchResultPosition = JSON.parse("null");
    
    var sectionType = JSON.parse("\"posts\"");
    
    var kind = JSON.parse("\"page\"");
    
    var fuse = null;

    if (enableSearch) {
      (function initFuse() {
        var xhr = new XMLHttpRequest();
        if (sectionType === "publication" && kind !== "page") {
          xhr.open('GET', permalink + "index.json");
        } else {
          xhr.open('GET', baseurl + langprefix + "/index.json");
        }
        
        xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
        xhr.onload = function () {
          if (xhr.status === 200) {
            fuse = new Fuse(JSON.parse(xhr.response.toString('utf-8')), {
              keys: sectionType.includes('publication') ? ['title', 'abstract'] : ['title', 'description', 'content'],
              includeMatches: enableSearchHighlight,
              shouldSort: true,
              threshold: 0.4,
              location: 0,
              distance: 100,
              maxPatternLength: 32,
              minMatchCharLength: 1,
            });
            window.fuse = fuse;
          }
          else {
            console.error('[' + xhr.status + ']Error:', xhr.statusText);
          }
        };
        xhr.send();
      })();
    }

    function makeLi(ulElem, obj) {
      var li = document.createElement('li');
      li.className = 'search-result__item';
      
      var a = document.createElement('a');
      a.innerHTML = obj.title;
      a.setAttribute('class', 'search-result__item--title');
      a.setAttribute('href', obj.permalink);

      var descDiv = document.createElement('div');
      descDiv.setAttribute('class', 'search-result__item--desc');
      if (obj.description) {
        descDiv.innerHTML = obj.description;
      } else if (obj.content) {
        descDiv.innerHTML = obj.content.substring(0, 225);
      }
      
      li.appendChild(a);
      li.appendChild(descDiv);
      ulElem.appendChild(li);
    }

    function makeHighlightLi(ulElem, obj) {
      var li = document.createElement('li');
      li.className = 'search-result__item';
      var descDiv = null;

      var a = document.createElement('a');
      a.innerHTML = obj.item.title;
      a.setAttribute('class', 'search-result__item--title');
      a.setAttribute('href', obj.item.uri);

      if (obj.matches && obj.matches.length) {
        for (var i = 0; i < obj.matches.length; i++) {
          if ('title' === obj.matches[i].key) {
            a = document.createElement('a');
            a.innerHTML = generateHighlightedText(obj.matches[i].value, obj.matches[i].indices);
            a.setAttribute('class', 'search-result__item--title');
            a.setAttribute('href', obj.item.uri);
          }
          
          if ('description' === obj.matches[i].key) {
            descDiv = document.createElement('div');
            descDiv.setAttribute('class', 'search-result__item--desc');
            descDiv.innerHTML = generateHighlightedText(obj.item.description, obj.matches[i].indices);
          } else if ('content' === obj.matches[i].key) {
            if (!descDiv) {
              descDiv = document.createElement('div');
              descDiv.setAttribute('class', 'search-result__item--desc');
              descDiv.innerHTML = generateHighlightedText(obj.item.content.substring(0, 150), obj.matches[i].indices);
            }
          } else {
            if (obj.item.description) {
              descDiv = document.createElement('div');
              descDiv.setAttribute('class', 'search-result__item--desc');
              descDiv.innerHTML = obj.item.description;
            } else {
              descDiv = document.createElement('div');
              descDiv.setAttribute('class', 'search-result__item--desc');
              descDiv.innerHTML = obj.item.content.substring(0, 150);
            }
          }
        }

        li.appendChild(a);
        if (descDiv) {
          li.appendChild(descDiv);
        }
        if (li) {
          ulElem.appendChild(li);
        }
      }
    }

    function renderSearchResultsSide(searchText, results) {
      searchResults = document.getElementById('search-results');
      searchMenu = document.getElementById('search-menu');
      searchResults.setAttribute('class', 'dropdown is-active');
      
      var ul = document.createElement('ul');
      ul.setAttribute('class', 'dropdown-content search-content');

      if (results.length) {
        results.forEach(function (result) {
          var li = document.createElement('li');
          var a = document.createElement('a');
          a.setAttribute('href', result.uri);
          a.setAttribute('class', 'dropdown-item');
          a.appendChild(li);

          var titleDiv = document.createElement('div');
          titleDiv.innerHTML = result.title;
          titleDiv.setAttribute('class', 'menu-item__title');

          var descDiv = document.createElement('div');
          descDiv.setAttribute('class', 'menu-item__desc');
          if (result.description) {
            descDiv.innerHTML = result.description;
          } else if (result.content) {
            descDiv.innerHTML = result.content.substring(0, 150);
          }

          li.appendChild(titleDiv);
          li.appendChild(descDiv);
          ul.appendChild(a);
        });
      } else {
        var li = document.createElement('li');
        li.setAttribute('class', 'dropdown-item');
        li.innerText = 'No results found';
        ul.appendChild(li);
      }

      while (searchMenu.hasChildNodes()) {
        searchMenu.removeChild(
          searchMenu.lastChild
        );
      }
      
      searchMenu.appendChild(ul);
    }

    function renderSearchHighlightResultsSide(searchText, results) {
      searchResults = document.getElementById('search-results');
      searchMenu = document.getElementById('search-menu');
      searchResults.setAttribute('class', 'dropdown is-active');

      var ul = document.createElement('ul');
      ul.setAttribute('class', 'dropdown-content search-content');

      if (results.length) {
        results.forEach(function (result) {
          var li = document.createElement('li');
          var a = document.createElement('a');
          var descDiv = null;

          a.setAttribute('href', result.item.uri);
          a.setAttribute('class', 'dropdown-item');
          a.appendChild(li);

          var titleDiv = document.createElement('div');
          titleDiv.innerHTML = result.item.title;
          titleDiv.setAttribute('class', 'menu-item__title');
          
          if (result.matches && result.matches.length) {
            for (var i = 0; i < result.matches.length; i++) {
              if ('title' === result.matches[i].key) {
                titleDiv.innerHTML = generateHighlightedText(result.matches[i].value, result.matches[i].indices);
              }

              if ('description' === result.matches[i].key) {
                descDiv = document.createElement('div');
                descDiv.setAttribute('class', 'menu-item__desc');
                descDiv.innerHTML = generateHighlightedText(result.item.description, result.matches[i].indices);
              } else if ('content' === result.matches[i].key) {
                if (!descDiv) {
                  descDiv = document.createElement('div');
                  descDiv.setAttribute('class', 'menu-item__desc');
                  descDiv.innerHTML = generateHighlightedText(result.item.content.substring(0, 150), result.matches[i].indices);
                }
              } else {
                if (result.item.description) {
                  descDiv = document.createElement('div');
                  descDiv.setAttribute('class', 'menu-item__desc');
                  descDiv.innerHTML = result.item.description;
                } else {
                  descDiv = document.createElement('div');
                  descDiv.setAttribute('class', 'menu-item__desc');
                  descDiv.innerHTML = result.item.content.substring(0, 150);
                }
              }
            }
            
            li.appendChild(titleDiv);
            if (descDiv) {
              li.appendChild(descDiv);
            }
            ul.appendChild(a);
          }
        });
      } else {
        var li = document.createElement('li');
        li.setAttribute('class', 'dropdown-item');
        li.innerText = 'No results found';
        ul.appendChild(li);
      }

      while (searchMenu.hasChildNodes()) {
        searchMenu.removeChild(
          searchMenu.lastChild
        );
      }
      searchMenu.appendChild(ul);
    }

    function renderSearchResultsMobile(searchText, results) {
      searchResults = document.getElementById('search-mobile-results');

      var content = document.createElement('div');
      content.setAttribute('class', 'mobile-search__content');

      if (results.length > 0) {
        results.forEach(function (result) {
          var item = document.createElement('a');
          item.setAttribute('href', result.uri);
          item.innerHTML = '<div class="mobile-search__item"><div class="mobile-search__item--title">📄 ' + result.title + '</div><div class="mobile-search__item--desc">' + (result.description ? result.description : result.content) + '</div></div>';
          content.appendChild(item);
        });
      } else {
        var item = document.createElement('span');
        content.appendChild(item);
      }

      let wrap = document.getElementById('search-mobile-results');
      while (wrap.firstChild) {
        wrap.removeChild(wrap.firstChild)
      }
      searchResults.appendChild(content);      
    }

    function renderSearchHighlightResultsMobile(searchText, results) {
      searchResults = document.getElementById('search-mobile-results');

      var ul = document.createElement('div');
      ul.setAttribute('class', 'mobile-search__content');

      if (results.length) {
        results.forEach(function (result) {
          var li = document.createElement('li');
          var a = document.createElement('a');
          var descDiv = null;

          a.setAttribute('href', result.item.uri);
          a.appendChild(li);
          li.setAttribute('class', 'mobile-search__item');

          var titleDiv = document.createElement('div');
          titleDiv.innerHTML = result.item.title;
          titleDiv.setAttribute('class', 'mobile-search__item--title');
          
          if (result.matches && result.matches.length) {
            for (var i = 0; i < result.matches.length; i++) {
              if ('title' === result.matches[i].key) {
                titleDiv.innerHTML = generateHighlightedText(result.matches[i].value, result.matches[i].indices);
              }

              if ('description' === result.matches[i].key) {
                descDiv = document.createElement('div');
                descDiv.setAttribute('class', 'mobile-search__item--desc');
                descDiv.innerHTML = generateHighlightedText(result.item.description, result.matches[i].indices);
              } else if ('content' === result.matches[i].key) {
                if (!descDiv) {
                  descDiv = document.createElement('div');
                  descDiv.setAttribute('class', 'mobile-search__item--desc');
                  descDiv.innerHTML = generateHighlightedText(result.item.content.substring(0, 150), result.matches[i].indices);
                }
              } else {
                if (result.item.description) {
                  descDiv = document.createElement('div');
                  descDiv.setAttribute('class', 'mobile-search__item--desc');
                  descDiv.innerHTML = result.item.description;
                } else {
                  descDiv = document.createElement('div');
                  descDiv.setAttribute('class', 'mobile-search__item--desc');
                  descDiv.innerHTML = result.item.content.substring(0, 150);
                }
              }
            }
            
            li.appendChild(titleDiv);
            if (descDiv) {
              li.appendChild(descDiv);
            }
            ul.appendChild(a);
          }
        });
      } else {
        var item = document.createElement('span');
        ul.appendChild(item);
      }

      let wrap = document.getElementById('search-mobile-results');
      while (wrap.firstChild) {
        wrap.removeChild(wrap.firstChild)
      }
      searchResults.appendChild(ul);
    }

    function generateHighlightedText(text, regions) {
      if (!regions) {
        return text;
      }

      var content = '', nextUnhighlightedRegionStartingIndex = 0;

      regions.forEach(function(region) {
        if (region[0] === region[1]) {
          return null;
        }
        
        content += '' +
          text.substring(nextUnhighlightedRegionStartingIndex, region[0]) +
          '<span class="search__highlight">' +
            text.substring(region[0], region[1] + 1) +
          '</span>' +
        '';
        nextUnhighlightedRegionStartingIndex = region[1] + 1;
      });

      content += text.substring(nextUnhighlightedRegionStartingIndex);

      return content;
    };

    var searchElem = document.getElementById('search');
    var searchMobile = document.getElementById('search-mobile');
    var searchResultsContainer = document.getElementById('search-results');

    searchElem ?
    searchElem.addEventListener('input', function(e) {
      if (!e.target.value | window.innerWidth < 770) {
        searchResultsContainer ? searchResultsContainer.setAttribute('class', 'dropdown') : null;
        searchResult ? searchResult.setAttribute('data-display', 'none') : null;
        summaryContainer ? summaryContainer.setAttribute('data-display', 'block') : null;
        return null;
      }

      searchText = e.target.value;
      var results = fuse.search(e.target.value);
      
      if (searchResultPosition === "main") {
        if (enableSearchHighlight) {
          renderSearchHighlightResultsMain(searchText, results);
        } else {
          renderSearchResultsMain(searchText, results);
        }
      } else {
        if (enableSearchHighlight) {
          renderSearchHighlightResultsSide(searchText, results);
        } else {
          renderSearchResultsSide(searchText, results);
        }
        
        var dropdownItems = searchResultsContainer.querySelectorAll('.dropdown-item');
        dropdownItems ? dropdownItems.forEach(function(item) {
          item.addEventListener('mousedown', function(e) {
            e.target.click();
          });
        }) : null;
      }
    }) : null;

    searchElem ? 
    searchElem.addEventListener('blur', function() {
      if (window.innerWidth < 770) {
        return null;
      }
      searchResultsContainer ? searchResultsContainer.setAttribute('class', 'dropdown') : null;
    }) : null;

    searchElem ? 
    searchElem.addEventListener('click', function(e) {
      if (window.innerWidth < 770) {
        return null;
      }
      if (!e.target.value) {
        searchResultsContainer ? searchResultsContainer.setAttribute('class', 'dropdown') : null;
        return null;
      }

      searchText = e.target.value;
      var results = fuse.search(e.target.value);

      if (searchResultPosition === "main") {
        if (enableSearchHighlight) {
          renderSearchHighlightResultsMain(searchText, results);
        } else {
          renderSearchResultsMain(searchText, results);
        }
      } else{
        if (enableSearchHighlight) {
          renderSearchHighlightResultsSide(searchText, results);
        } else {
          renderSearchResultsSide(searchText, results);
        }

        var dropdownItems = searchResultsContainer.querySelectorAll('.dropdown-item');
        dropdownItems ? dropdownItems.forEach(function (item) {
          item.addEventListener('mousedown', function (e) {
            e.target.click();
          });
        }) : null;
      }
    }) : null;

    var searchMenuElem = document.getElementById("search-menu");
    var activeItem = document.querySelector('#search-menu .dropdown-item.is-active');
    var activeIndex = null;
    var items = null;
    var searchContainerMaxHeight = 350;

    searchElem ? 
    searchElem.addEventListener('keydown', function(e) {
      if (window.innerWidth < 770) {
        return null;
      }

      if (e.key === 'Escape') {
        searchResult ? searchResult.setAttribute('data-display', 'none') : null;
        summaryContainer ? summaryContainer.setAttribute('data-display', 'block') : null;
      }

      var items = document.querySelectorAll('#search-menu .dropdown-item');
      var keyCode = e.which || e.keyCode;

      if (!items || !items.length) {
        return null;
      }
      
      if (e.key === 'ArrowDown' || keyCode === 40) {
        if (activeIndex === null) {
          activeIndex = 0;
          items[activeIndex].classList.remove('is-active');
        } else {
          items[activeIndex].classList.remove('is-active');
          activeIndex = activeIndex === items.length - 1 ? 0 : activeIndex + 1;
        }
        items[activeIndex].classList.add('is-active');

        let overflowedPixel = items[activeIndex].offsetTop + items[activeIndex].clientHeight - searchContainerMaxHeight;
        if (overflowedPixel > 0) {
          document.querySelector(".search-content").scrollTop += items[activeIndex].getBoundingClientRect().height;
        } else if (activeIndex === 0) {
          document.querySelector(".search-content").scrollTop = 0;
        }
      } else if (e.key === 'ArrowUp' || keyCode === 38) {
        if (activeIndex === null) {
          activeIndex = items.length - 1;
          items[activeIndex].classList.remove('is-active');
        } else {
          items[activeIndex].classList.remove('is-active');
          activeIndex = activeIndex === 0 ? items.length - 1 : activeIndex - 1;
        }
        items[activeIndex].classList.add('is-active');
        
        let overflowedPixel = items[activeIndex].offsetTop + items[activeIndex].clientHeight - searchContainerMaxHeight;
        if (overflowedPixel < 0) {
          document.querySelector(".search-content").scrollTop -= items[activeIndex].getBoundingClientRect().height;
        } else {
          document.querySelector(".search-content").scrollTop = overflowedPixel + items[activeIndex].getBoundingClientRect().height;
        }
      } else if (e.key === 'Enter' || keyCode === 13) {
        if (items[activeIndex] && items[activeIndex].getAttribute('href')) {
          location.href = items[activeIndex].getAttribute('href');
        }
      } else if (e.key === 'Escape' || keyCode === 27) {
        e.target.value = null;
        if (searchResults) {
          searchResults.classList.remove('is-active');
        }
      }
    }) : null;

    searchMobile ? 
    searchMobile.addEventListener('input', function(e) {
      if (!e.target.value) {
        let wrap = document.getElementById('search-mobile-results');
        while (wrap.firstChild) {
          wrap.removeChild(wrap.firstChild);
        }
        return null;
      }

      searchText = e.target.value;
      var results = fuse.search(e.target.value);
      renderSearchResultsMobile(searchText, results);
      if (enableSearchHighlight) {
        renderSearchHighlightResultsMobile(searchText, results);
      } else {
        renderSearchResultsMobile(searchText, results);
      }
    }) : null;
  


  
    var mobileSearchInputElem = document.querySelector('#search-mobile');
    var mobileSearchClassElem = document.querySelector('.mobile-search');
    var mobileSearchBtnElem = document.querySelector('#mobileSearchBtn');
    var mobileSearchCloseBtnElem = document.querySelector('#search-mobile-close');
    var mobileSearchContainer = document.querySelector('#search-mobile-container');
    var mobileSearchResultsElem = document.querySelector('#search-mobile-results');
    var htmlElem = document.querySelector('html');

    if (mobileSearchClassElem) {
      mobileSearchClassElem.style.display = 'none';
    }

    mobileSearchBtnElem ? 
    mobileSearchBtnElem.addEventListener('click', function () {
      if (mobileSearchContainer) {
        mobileSearchContainer.style.display = 'block';
      }

      if (mobileSearchInputElem) {
        mobileSearchInputElem.focus();
      }

      if (htmlElem) {
        htmlElem.style.overflowY = 'hidden';
      }
    }) : null;

    mobileSearchCloseBtnElem ? 
    mobileSearchCloseBtnElem.addEventListener('click', function() {
      if (mobileSearchContainer) {
        mobileSearchContainer.style.display = 'none';
      }

      if (mobileSearchInputElem) {
        mobileSearchInputElem.value = '';
      }
      
      if (mobileSearchResultsElem) {
        while (mobileSearchResultsElem.firstChild) {
          mobileSearchResultsElem.removeChild(mobileSearchResultsElem.firstChild);
        }
      }

      if (htmlElem) {
        htmlElem.style.overflowY = 'visible';
      }
    }) : null;

    mobileSearchInputElem ?
    mobileSearchInputElem.addEventListener('keydown', function(e) {
      var keyCode = e.which || e.keyCode;
      if (e.key === 'Escape' || keyCode === 27) {
        if (mobileSearchContainer) {
          mobileSearchContainer.style.display = 'none';
        }
        
        if (mobileSearchInputElem) {
          mobileSearchInputElem.value = '';
        }

        if (mobileSearchResultsElem) {
          while (mobileSearchResultsElem.firstChild) {
            mobileSearchResultsElem.removeChild(mobileSearchResultsElem.firstChild);
          }
        }
        if (htmlElem) {
          htmlElem.style.overflowY = 'visible';
        }
      }
    }) : null;
  


  
    function renderSearchResultsMain(searchText, results) {
      var searchBody = document.querySelector('.search-result__body');
      var originUl = searchBody.querySelector('ul');
      var ul = document.createElement('ul');
      
      if (!searchText) {
        searchResult ? searchResult.setAttribute('data-display', 'none') : null;
        summaryContainer ? summaryContainer.setAttribute('data-display', 'block') : null;
      } else if (results) {
        if (results && results.length) {
          results.forEach(function (result) {
            makeLi(ul, result);
          });

          searchResult ? searchResult.setAttribute('data-display', 'block') : null;
          summaryContainer ? summaryContainer.setAttribute('data-display', 'none') : null;
        }
      }

      originUl.parentNode.replaceChild(ul, originUl);
    }

    function renderSearchHighlightResultsMain(searchText, results) {
      var searchBody = document.querySelector('.search-result__body');
      var originUl = searchBody.querySelector('ul');
      var ul = document.createElement('ul');

      if (!searchText) {
        searchResult ? searchResult.setAttribute('data-display', 'none') : null;
        summaryContainer ? summaryContainer.setAttribute('data-display', 'block') : null;
      } else if (results) {
        if (results && results.length) {
          results.forEach(function (result) {
            makeHighlightLi(ul, result);
          });

          searchResult ? searchResult.setAttribute('data-display', 'block') : null;
          summaryContainer ? summaryContainer.setAttribute('data-display', 'none') : null;
        }
      }

      originUl.parentNode.replaceChild(ul, originUl);
    }
  
  });
</script>    
    


<link rel="stylesheet" href="/css/main.min.css">


    
<meta name="description" content="Ji Yang(YangJi) blog." />


<meta name="created" content="2019-10-19T20:53:02&#43;0000">
<meta name="modified" content="2019-10-19T20:53:02&#43;0000">
<meta property="article:published_time" content="2019-10-19T20:53:02&#43;0000">

<meta name="author" content="Yang">


<meta property="og:site_name" content="Yang Blog">
<meta property="og:title" content="Android 中 MessageQueue 的 nativePollOnce">
<meta property="og:url" content="https://blog.jiyang.site/posts/2019-10-19-android%E4%B8%ADmessagequeue%E7%9A%84nativepollonce/">
<meta property="og:type" content="article">
<meta property="og:description" content="Ji Yang(YangJi) blog.">

<meta name="generator" content="Hugo 0.74.3" />
<meta name="msapplication-TileColor" content="#fff">

<meta name="theme-color" content="#fff">

<meta name="msapplication-navbutton-color" content="#fff">

<meta name="apple-mobile-web-app-status-bar-style" content="#fff">

<link rel="canonical" href="https://blog.jiyang.site/posts/2019-10-19-android%E4%B8%ADmessagequeue%E7%9A%84nativepollonce/">

<link rel="manifest" href="/manifest.json">

  
  <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
  <link rel="icon" href="/favicon.png" sizes="any" type="image/png" />
  


    <script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "WebPage",
    "headline": "Android 中 MessageQueue 的 nativePollOnce",
    "datePublished": "2019-10-19T20:53:02Z",
    "dateModified": "2019-10-19T20:53:02Z",
    "url" : "https://blog.jiyang.site/posts/2019-10-19-android%E4%B8%ADmessagequeue%E7%9A%84nativepollonce/",
    "description": "\u003cp\u003eAndroid SDK 中的事件循环已经是一个老生常谈的问题了, 像 \u003ccode\u003eHandler\u003c/code\u003e \u003ccode\u003eLooper\u003c/code\u003e \u003ccode\u003eMessageQueue\u003c/code\u003e 这几个类也是被大家研究透彻了.\u003cbr /\u003e 但是再回头看以前自己的分析, 总感觉差点什么, 不够透彻. 心里隐隐感觉自己没有把事情完全吃透, 于是今日又回顾 Android 中的事件循环机制, 注意到\u003cbr /\u003e \u003ccode\u003eMessageQueue …\u003c/code\u003e\u003c/p\u003e",
    "mainEntityOfPage": {
      "@type": "WebPage",
      "@id": "https://blog.jiyang.site/"
    },
    "publisher": {
      "@type": "Organization",
      "name": "Yang Blog",
      "url": "https://blog.jiyang.site/"
    }
  }
</script>

    
  
  






  <script>
    
    var baiduAnalyticsId = JSON.parse("\"22764a4cf09dab78361f10e181619e39\"");

    var _hmt = _hmt || [];
    (function () {
      var hm = document.createElement("script");
      hm.src = "https://hm.baidu.com/hm.js?" + baiduAnalyticsId;
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
  </script>


    
</head>

<body id="root" class="theme__light">
    <script>
        var localTheme = localStorage.getItem('theme');
        if (localTheme) {
            document.getElementById('root').className = 'theme__' + localTheme;
        }
    </script>
    <div id="container">
        





        <div class="wrapper" data-type="posts" data-kind="page">
            <nav class="navbar" role="navigation" aria-label="main navigation" data-dir="ltr">
  <div class="navbar__brand">
    
    &nbsp;&nbsp;
    
    
      <a href="/" title="Home" rel="home" class="navbar__title-link">
        <h6 class="navbar__title">YangBlog</h6>
      </a>
    
  </div>

  
<div class="theme theme-mobile" data-ani="true">
  <div class="dropdown">
    <button class="dropdown-trigger navbar__slide-down" aria-label="Select Theme Button" style="" data-ani="true">
      <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24"><path fill="none" d="M24 0H0v24h24V0z"/><path fill="currentColor" d="M6.34 7.93c-3.12 3.12-3.12 8.19 0 11.31C7.9 20.8 9.95 21.58 12 21.58s4.1-.78 5.66-2.34c3.12-3.12 3.12-8.19 0-11.31l-4.95-4.95c-.39-.39-1.02-.39-1.41 0L6.34 7.93zM12 19.59c-1.6 0-3.11-.62-4.24-1.76C6.62 16.69 6 15.19 6 13.59s.62-3.11 1.76-4.24L12 5.1v14.49z"/></svg>      
    </button>
    <div class="dropdown-content select-theme">
      
        
        <a href="#" class="dropdown-item select-theme__item is-active">
          light
        </a>
        
        <a href="#" class="dropdown-item select-theme__item ">
          dark
        </a>
        
        <a href="#" class="dropdown-item select-theme__item ">
          hacker
        </a>
        
        <a href="#" class="dropdown-item select-theme__item ">
          solarized
        </a>
        
        <a href="#" class="dropdown-item select-theme__item ">
          kimbie
        </a>
        
      
    </div>
  </div>
</div>


<div id="mobileSearchBtn" class="mobile-search__btn" data-ani="true">
  <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" fill="currentColor" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M15.5 14h-.79l-.28-.27c1.2-1.4 1.82-3.31 1.48-5.34-.47-2.78-2.79-5-5.59-5.34-4.23-.52-7.79 3.04-7.27 7.27.34 2.8 2.56 5.12 5.34 5.59 2.03.34 3.94-.28 5.34-1.48l.27.28v.79l4.25 4.25c.41.41 1.08.41 1.49 0 .41-.41.41-1.08 0-1.49L15.5 14zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/></svg>
</div>

<div id="search-mobile-container" class="mobile-search hide" data-dir="ltr">
  <div class="mobile-search__top">
    <input id="search-mobile" type="text" aria-label="Mobile Search" placeholder="Search" class="mobile-search__top--input"/>
    <div id="search-mobile-close" class="mobile-search__top--icon">
      <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24"><path opacity=".87" fill="none" d="M0 0h24v24H0V0z"/><path fill="currentColor" d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm3.59-13L12 10.59 8.41 7 7 8.41 10.59 12 7 15.59 8.41 17 12 13.41 15.59 17 17 15.59 13.41 12 17 8.41z"/></svg>
    </div>
  </div>
  <div id="search-mobile-results" class="mobile-search__body">
    
  </div>
</div>


<a role="button" class="navbar__burger" aria-label="menu" aria-expanded="false"
  data-ani="true">
  <span aria-hidden="true"></span>
  <span aria-hidden="true"></span>
  <span aria-hidden="true"></span>
</a>
<div class="navbarm__collapse" data-open="false">
  <ul dir="ltr">
    
    
      
      
      
      

      
        <li class="navbarm__menu--item ">
          <a href="/categories">category</a>
        </li>
      
      
    
      
      
      
      

      
        <li class="navbarm__menu--item active">
          <a href="/posts">posts</a>
        </li>
      
      
    

    
      <li class="navbarm__menu--item ">
        <a href="/tags" class="navbarm__menu--term" data-index="0">
          Tags
        </a>
      </li>
    
      <li class="navbarm__menu--item ">
        <a href="/categories" class="navbarm__menu--term" data-index="1">
          Categories
        </a>
      </li>
    
      <li class="navbarm__menu--item ">
        <a href="/series" class="navbarm__menu--term" data-index="2">
          Series
        </a>
      </li>
    
  </ul>
</div>
  <div class="navbar__menu">
  
<div class="theme" data-ani="true">
  <div class="dropdown">
    <button class="dropdown-trigger navbar__slide-down" aria-label="Select Theme Button" data-ani="true">
      <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24"><path fill="none" d="M24 0H0v24h24V0z"/><path fill="currentColor" d="M6.34 7.93c-3.12 3.12-3.12 8.19 0 11.31C7.9 20.8 9.95 21.58 12 21.58s4.1-.78 5.66-2.34c3.12-3.12 3.12-8.19 0-11.31l-4.95-4.95c-.39-.39-1.02-.39-1.41 0L6.34 7.93zM12 19.59c-1.6 0-3.11-.62-4.24-1.76C6.62 16.69 6 15.19 6 13.59s.62-3.11 1.76-4.24L12 5.1v14.49z"/></svg>      
    </button>
    <div class="dropdown-content select-theme">
      
        
        <a href="#" class="dropdown-item select-theme__item is-active">
          light
        </a>
        
        <a href="#" class="dropdown-item select-theme__item ">
          dark
        </a>
        
        <a href="#" class="dropdown-item select-theme__item ">
          hacker
        </a>
        
        <a href="#" class="dropdown-item select-theme__item ">
          solarized
        </a>
        
        <a href="#" class="dropdown-item select-theme__item ">
          kimbie
        </a>
        
      
    </div>
  </div>
</div>

  
  
  
  
  
  
  
  <a href="/categories" class="navbar__menu-item navbar__slide-down " dir="ltr" data-ani="true">category</a>
  
  
  
  
  
  
  
  <a href="/posts" class="navbar__menu-item navbar__slide-down active" dir="ltr" data-ani="true">posts</a>
  
  
</div>
</nav>
            
            

<main class="single__main main-main">
  
    <nav class="breadcrumb hide" aria-label="breadcrumbs">
  <script>document.querySelector('.breadcrumb').classList.remove('hide')</script>
  <ol>
    
  
  
  
  
  
  <li >
    
      <a href="https://blog.jiyang.site/" class="capitalize">Yang Blog</a>
    
  </li>
  
  
  <li >
    
      <a href="https://blog.jiyang.site/posts/" class="capitalize">Posts</a>
    
  </li>
  
  
  <li  class="is-active" >
    
      <span>Android 中 MessageQueue 的 nativePollOnce</span>
    
  </li>
  
  </ol>
  
</nav>
  
  
  <div class="single ">
    <div class="single__nojs">This page looks best with JavaScript enabled</div>
    <script>document.querySelector('.single').classList.remove('hide'); document.querySelector('.single__nojs').classList.add('hide');</script>
    <h2 class="single__title" data-ani="true">Android 中 MessageQueue 的 nativePollOnce</h2>
    <div class="single__meta">
      
<div class="single__infos">
  <time class="single__info" title="Written At">📅&nbsp;Oct 19, 2019 </time>
  
  &nbsp;&middot;&nbsp; <span class="single__info" title="Reading Time"> ☕&nbsp;7&nbsp;min read </span>
  
  <span class="single__info">
    
  </span>
</div>
      
<ul class="single__tags caption">
  

</ul>
    </div>
    <article class="single__contents" data-dir="ltr" data-ani="true">
      
      <p>Android SDK 中的事件循环已经是一个老生常谈的问题了, 像 <code>Handler</code> <code>Looper</code> <code>MessageQueue</code> 这几个类也是被大家研究透彻了.<br />
但是再回头看以前自己的分析, 总感觉差点什么, 不够透彻. 心里隐隐感觉自己没有把事情完全吃透, 于是今日又回顾 Android 中的事件循环机制, 注意到<br />
<code>MessageQueue</code> 中获取下一条消息时会执行一个 native 调用 <code>nativePollOnce</code>, 翻看 Android 系统源码发现有内容.</p>
<h2 id="来自高手的解释">来自高手的解释</h2>
<blockquote>
<p>首先, 先梭哈一把 stackoverflow 上高手对这个问题(<a href="https://stackoverflow.com/questions/38818642/android-what-is-message-queue-native-poll-once-in-android">android - what is message queue native poll once in android?</a>)的回答原文:</p>
</blockquote>
<p>Short answer:</p>
<p>The nativePollOnce method is used to &ldquo;wait&rdquo; till the next Message becomes available. If the time spent during this call is long, your main (UI) thread has no real work to do and waits for next events to process. There&rsquo;s no need to worry about that.</p>
<p>Explanation:</p>
<p>Because the &ldquo;main&rdquo; thread is responsible for drawing UI and handling various events, it&rsquo;s Runnable has a loop which processes all these events. The loop is managed by a Looper and its job is quite straightforward: it processes all Messages in the MessageQueue.</p>
<p>A Message is added to the queue for example in response to input events, as frame rendering callback or even your own Handler.post calls. Sometimes the main thread has no work to do (that is, no messages in the queue), which may happen e.g. just after finishing rendering single frame (the thread has just drawn one frame and is ready for the next one, just waits for a proper time). Two Java methods in the MessageQueue class are interesting to us: Message next() and boolean enqueueMessage(Message, long). Message next(), as its name suggest, takes and returns the next Message from the queue. If the queue is empty (and there&rsquo;s nothing to return), the method calls native void nativePollOnce(long, int) which blocks until a new message is added. At this point you might ask how does nativePollOnce know when to wake up. That&rsquo;s a very good question. When a Message is added to the queue, the framework calls the enqueueMessage method, which not only inserts the message into the queue, but also calls native static void nativeWake(long), if there&rsquo;s need to wake up the queue. The core magic of nativePollOnce and nativeWake happens in the native (actually, C++) code. Native MessageQueue utilizes a Linux system call named epoll, which allows to monitor a file descriptor for IO events. nativePollOnce calls epoll_wait on a certain file descriptor, whereas nativeWake writes to the descriptor, which is one of the IO operations, epoll_wait waits for. The kernel then takes out the epoll-waiting thread from the waiting state and the thread proceeds with handling the new message. If you&rsquo;re familiar with Java&rsquo;s Object.wait() and Object.notify() methods, you can imagine that nativePollOnce is a rough equivalent for Object.wait() and nativeWake for Object.notify(), except they&rsquo;re implemented completely differently: nativePollOnce uses epoll and Object.wait() uses futex Linux call. It&rsquo;s worth noticing that neither nativePollOnce nor Object.wait() waste CPU cycles, as when a thread enters either method, it becomes disabled for thread scheduling purposes (quoting the javadoc for the Object class). However, some profilers may mistakenly recognize epoll-waiting (or even Object-waiting) threads as running and consuming CPU time, which is incorrect. If those methods actually wasted CPU cycles, all idle apps would use 100% of the CPU, heating and slowing down the device.</p>
<p>Conclusion:</p>
<p>You shouldn&rsquo;t worry about nativePollOnce. It just indicates that processing of all Messages has been finished and the thread waits for the next one. Well, that simply means you don&rsquo;t give too much work to your main thread ;)</p>
<hr />
<p>translate.google 一下 😬:</p>
<p><strong>简短答案:</strong></p>
<p><code>nativePollOnce</code> 方法用于“等待”, 直到下一条消息可用为止. 如果在此调用期间花费的时间很长, 则您的主线程没有实际工作要做, 而是等待下一个事件处理.无需担心.</p>
<p><strong>说明:</strong></p>
<p>因为主线程负责绘制 UI 和处理各种事件, 所以主线程拥有一个处理所有这些事件的循环. 该循环由 <code>L​​ooper</code> 管理, 其工作非常简单: 它处理 <code>MessageQueue</code> 中的所有 <code>Message</code>.<br />
例如, 响应于输入事件, 将消息添加到队列, 帧渲染回调, 甚至您的 <code>Handler.post</code> 调用. 有时主线程无事可做（即队列中没有消息), 例如在完成渲染单帧之后(线程刚绘制了一帧, 并准备好下一帧, 等待适当的时间). <code>MessageQueue</code> 类中的两个 Java 方法对我们很有趣: <code>Message next()</code>和 <code>boolean enqueueMessage(Message, long)</code>. 顾名思义, <code>Message next()</code> 从队列中获取并返回下一个消息. 如果队列为空(无返回值), 则该方法将调用 <code>native void nativePollOnce(long, int)</code>, 该方法将一直阻塞直到添加新消息为止. 此时,您可能会问<code>nativePollOnce</code> 如何知道何时醒来. 这是一个很好的问题. 当将 <code>Message</code> 添加到队列时, 框架调用 <code>enqueueMessage</code> 方法, 该方法不仅将消息插入队列, 而且还会调用<code>native static void nativeWake(long)</code>. <code>nativePollOnce</code> 和 <code>nativeWake</code> 的核心魔术发生在 native 代码中. native <code>MessageQueue</code> 利用名为 <code>epoll</code> 的 Linux 系统调用, 该系统调用可以监视文件描述符中的 IO 事件. <code>nativePollOnce</code> 在某个文件描述符上调用 <code>epoll_wait</code>, 而 <code>nativeWake</code> 写入一个 IO 操作到描述符, <code>epoll_wait</code> 等待. 然后, 内核从等待状态中取出 <code>epoll</code> 等待线程, 并且该线程继续处理新消息. 如果您熟悉 Java 的 <code>Object.wait()</code>和 <code>Object.notify()</code>方法,可以想象一下 <code>nativePollOnce</code> 大致等同于 <code>Object.wait()</code>, <code>nativeWake</code> 等同于 <code>Object.notify()</code>,但它们的实现完全不同: <code>nativePollOnce</code> 使用 <code>epoll</code>, 而 <code>Object.wait</code> 使用 <code>futex</code> Linux 调用. 值得注意的是, <code>nativePollOnce</code> 和 <code>Object.wait</code> 都不会浪费 CPU 周期, 因为当线程进入任一方法时, 出于线程调度的目的, 该线程将被禁用(引用Object类的javadoc). 但是, 某些事件探查器可能会错误地将等待 <code>epoll</code> 等待(甚至是 Object.wait)的线程识别为正在运行并消耗 CPU 时间, 这是不正确的. 如果这些方法实际上浪费了 CPU 周期, 则所有空闲的应用程序都将使用 100％ 的 CPU, 从而加热并降低设备速度.</p>
<p><strong>结论:</strong></p>
<p><code>nativePollOnce</code>. 它只是表明所有消息的处理已完成, 线程正在等待下一个消息.</p>
<h2 id="我以前的理解分享">我以前的理解分享</h2>
<p><img src="http://image.youcute.cn/image/blog/looper_main_thread_sleep.png" alt="Looper" /></p>
<p><img src="http://image.youcute.cn/image/blog/linux_io_model.png" alt="linux io model" /></p>
<p>Linux 有多个 IO 模型:</p>
<ul>
<li>阻塞 IO</li>
<li>非阻塞 IO</li>
<li>IO 复用, 对应 <code>select</code> <code>poll</code> <code>epoll</code> 都属于基于 IO 复用模式的调用</li>
<li>信号驱动 IO</li>
<li>异步 IO</li>
</ul>
<p><img src="http://image.youcute.cn/image/blog/io_multiplexing.png" alt="io multiplexing" /></p>
<h2 id="看下源码">看下源码</h2>
<h3 id="java-这边">Java 这边</h3>
<h4 id="enqueuemessage"><code>enqueueMessage</code>:</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-java" data-lang="java"><span class="kt">boolean</span> <span class="nf">enqueueMessage</span><span class="o">(</span><span class="n">Message</span> <span class="n">msg</span><span class="o">,</span> <span class="kt">long</span> <span class="n">when</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">if</span> <span class="o">(</span><span class="n">msg</span><span class="o">.</span><span class="na">target</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">throw</span> <span class="k">new</span> <span class="n">IllegalArgumentException</span><span class="o">(</span><span class="s">&#34;Message must have a target.&#34;</span><span class="o">);</span>
    <span class="o">}</span>
    <span class="k">if</span> <span class="o">(</span><span class="n">msg</span><span class="o">.</span><span class="na">isInUse</span><span class="o">())</span> <span class="o">{</span>
        <span class="k">throw</span> <span class="k">new</span> <span class="n">IllegalStateException</span><span class="o">(</span><span class="n">msg</span> <span class="o">+</span> <span class="s">&#34; This message is already in use.&#34;</span><span class="o">);</span>
    <span class="o">}</span>
    <span class="kd">synchronized</span> <span class="o">(</span><span class="k">this</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">msg</span><span class="o">.</span><span class="na">markInUse</span><span class="o">();</span>
        <span class="n">msg</span><span class="o">.</span><span class="na">when</span> <span class="o">=</span> <span class="n">when</span><span class="o">;</span>
        <span class="n">Message</span> <span class="n">p</span> <span class="o">=</span> <span class="n">mMessages</span><span class="o">;</span>
        <span class="kt">boolean</span> <span class="n">needWake</span><span class="o">;</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">p</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">||</span> <span class="n">when</span> <span class="o">==</span> <span class="n">0</span> <span class="o">||</span> <span class="n">when</span> <span class="o">&lt;</span> <span class="n">p</span><span class="o">.</span><span class="na">when</span><span class="o">)</span> <span class="o">{</span>
            <span class="c1">// New head, wake up the event queue if blocked.
</span><span class="c1"></span>            <span class="n">msg</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="n">p</span><span class="o">;</span>
            <span class="n">mMessages</span> <span class="o">=</span> <span class="n">msg</span><span class="o">;</span>
            <span class="n">needWake</span> <span class="o">=</span> <span class="n">mBlocked</span><span class="o">;</span>
        <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
            <span class="c1">// Inserted within the middle of the queue.  Usually we don&#39;t have to wake
</span><span class="c1"></span>            <span class="c1">// up the event queue unless there is a barrier at the head of the queue
</span><span class="c1"></span>            <span class="c1">// and the message is the earliest asynchronous message in the queue.
</span><span class="c1"></span>            <span class="n">needWake</span> <span class="o">=</span> <span class="n">mBlocked</span> <span class="o">&amp;&amp;</span> <span class="n">p</span><span class="o">.</span><span class="na">target</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="n">msg</span><span class="o">.</span><span class="na">isAsynchronous</span><span class="o">();</span>
            <span class="n">Message</span> <span class="n">prev</span><span class="o">;</span>
            <span class="k">for</span> <span class="o">(;;)</span> <span class="o">{</span>
                <span class="n">prev</span> <span class="o">=</span> <span class="n">p</span><span class="o">;</span>
                <span class="n">p</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>
                <span class="k">if</span> <span class="o">(</span><span class="n">p</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">||</span> <span class="n">when</span> <span class="o">&lt;</span> <span class="n">p</span><span class="o">.</span><span class="na">when</span><span class="o">)</span> <span class="o">{</span>
                    <span class="k">break</span><span class="o">;</span>
                <span class="o">}</span>
                <span class="k">if</span> <span class="o">(</span><span class="n">needWake</span> <span class="o">&amp;&amp;</span> <span class="n">p</span><span class="o">.</span><span class="na">isAsynchronous</span><span class="o">())</span> <span class="o">{</span>
                    <span class="n">needWake</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
                <span class="o">}</span>
            <span class="o">}</span>
            <span class="n">msg</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="n">p</span><span class="o">;</span> <span class="c1">// invariant: p == prev.next
</span><span class="c1"></span>            <span class="n">prev</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="n">msg</span><span class="o">;</span>
        <span class="o">}</span>
        <span class="c1">// We can assume mPtr != 0 because mQuitting is false.
</span><span class="c1"></span>        <span class="k">if</span> <span class="o">(</span><span class="n">needWake</span><span class="o">)</span> <span class="o">{</span>
            <span class="c1">// 这里唤醒 nativePollOnce 的沉睡
</span><span class="c1"></span>            <span class="n">nativeWake</span><span class="o">(</span><span class="n">mPtr</span><span class="o">);</span>
        <span class="o">}</span>
    <span class="o">}</span>
    <span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></td></tr></table>
</div>
</div><h4 id="next"><code>next</code>:</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-java" data-lang="java"><span class="n">Message</span> <span class="nf">next</span><span class="o">()</span> <span class="o">{</span>
    <span class="c1">//...
</span><span class="c1"></span>    <span class="kt">int</span> <span class="n">pendingIdleHandlerCount</span> <span class="o">=</span> <span class="o">-</span><span class="n">1</span><span class="o">;</span> <span class="c1">// -1 only during first iteration
</span><span class="c1"></span>    <span class="kt">int</span> <span class="n">nextPollTimeoutMillis</span> <span class="o">=</span> <span class="n">0</span><span class="o">;</span>
    <span class="k">for</span> <span class="o">(;;)</span> <span class="o">{</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">nextPollTimeoutMillis</span> <span class="o">!=</span> <span class="n">0</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">Binder</span><span class="o">.</span><span class="na">flushPendingCommands</span><span class="o">();</span>
        <span class="o">}</span>
        <span class="c1">// nativePollOnce 这里陷入沉睡, 等待唤醒
</span><span class="c1"></span>        <span class="n">nativePollOnce</span><span class="o">(</span><span class="n">ptr</span><span class="o">,</span> <span class="n">nextPollTimeoutMillis</span><span class="o">);</span>
        <span class="kd">synchronized</span> <span class="o">(</span><span class="k">this</span><span class="o">)</span> <span class="o">{</span>
            <span class="c1">// Try to retrieve the next message.  Return if found.
</span><span class="c1"></span>            <span class="kd">final</span> <span class="kt">long</span> <span class="n">now</span> <span class="o">=</span> <span class="n">SystemClock</span><span class="o">.</span><span class="na">uptimeMillis</span><span class="o">();</span>
            <span class="n">Message</span> <span class="n">prevMsg</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
            <span class="n">Message</span> <span class="n">msg</span> <span class="o">=</span> <span class="n">mMessages</span><span class="o">;</span>
            <span class="k">if</span> <span class="o">(</span><span class="n">msg</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="n">msg</span><span class="o">.</span><span class="na">target</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
                <span class="c1">// Stalled by a barrier.  Find the next asynchronous message in the queue.
</span><span class="c1"></span>                <span class="k">do</span> <span class="o">{</span>
                    <span class="n">prevMsg</span> <span class="o">=</span> <span class="n">msg</span><span class="o">;</span>
                    <span class="n">msg</span> <span class="o">=</span> <span class="n">msg</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>
                <span class="o">}</span> <span class="k">while</span> <span class="o">(</span><span class="n">msg</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">msg</span><span class="o">.</span><span class="na">isAsynchronous</span><span class="o">());</span>
            <span class="o">}</span>
            <span class="k">if</span> <span class="o">(</span><span class="n">msg</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
                <span class="k">if</span> <span class="o">(</span><span class="n">now</span> <span class="o">&lt;</span> <span class="n">msg</span><span class="o">.</span><span class="na">when</span><span class="o">)</span> <span class="o">{</span>
                    <span class="c1">// Next message is not ready.  Set a timeout to wake up when it is ready.
</span><span class="c1"></span>                    <span class="n">nextPollTimeoutMillis</span> <span class="o">=</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="n">Math</span><span class="o">.</span><span class="na">min</span><span class="o">(</span><span class="n">msg</span><span class="o">.</span><span class="na">when</span> <span class="o">-</span> <span class="n">now</span><span class="o">,</span> <span class="n">Integer</span><span class="o">.</span><span class="na">MAX_VALUE</span><span class="o">);</span>
                <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
                    <span class="c1">// Got a message.
</span><span class="c1"></span>                    <span class="n">mBlocked</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
                    <span class="k">if</span> <span class="o">(</span><span class="n">prevMsg</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
                        <span class="n">prevMsg</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="n">msg</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>
                    <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
                        <span class="n">mMessages</span> <span class="o">=</span> <span class="n">msg</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>
                    <span class="o">}</span>
                    <span class="n">msg</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
                    <span class="k">if</span> <span class="o">(</span><span class="n">DEBUG</span><span class="o">)</span> <span class="n">Log</span><span class="o">.</span><span class="na">v</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">&#34;Returning message: &#34;</span> <span class="o">+</span> <span class="n">msg</span><span class="o">);</span>
                    <span class="n">msg</span><span class="o">.</span><span class="na">markInUse</span><span class="o">();</span>
                    <span class="k">return</span> <span class="n">msg</span><span class="o">;</span>
                <span class="o">}</span>
            <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
                <span class="c1">// No more messages.
</span><span class="c1"></span>                <span class="n">nextPollTimeoutMillis</span> <span class="o">=</span> <span class="o">-</span><span class="n">1</span><span class="o">;</span>
            <span class="o">}</span>
            <span class="c1">//...
</span><span class="c1"></span>        <span class="o">}</span>
        <span class="c1">//...
</span><span class="c1"></span>    <span class="o">}</span>
<span class="o">}</span>
</code></pre></td></tr></table>
</div>
</div><h3 id="cpp-那边">CPP 那边</h3>
<h4 id="nativewake"><code>nativeWake</code></h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-cpp" data-lang="cpp"><span class="kt">void</span> <span class="n">NativeMessageQueue</span><span class="o">::</span><span class="n">wake</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">mLooper</span><span class="o">-&gt;</span><span class="n">wake</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-cpp" data-lang="cpp"><span class="kt">void</span> <span class="n">Looper</span><span class="o">::</span><span class="n">wake</span><span class="p">()</span> <span class="p">{</span>
    <span class="kt">uint64_t</span> <span class="n">inc</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="c1">// 调用 write 向 mWakeEventFd 描述符写入一个事件
</span><span class="c1"></span>    <span class="n">ssize_t</span> <span class="n">nWrite</span> <span class="o">=</span> <span class="n">TEMP_FAILURE_RETRY</span><span class="p">(</span><span class="n">write</span><span class="p">(</span><span class="n">mWakeEventFd</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">inc</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">uint64_t</span><span class="p">)));</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">nWrite</span> <span class="o">!=</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">uint64_t</span><span class="p">))</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">errno</span> <span class="o">!=</span> <span class="n">EAGAIN</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">LOG_ALWAYS_FATAL</span><span class="p">(</span><span class="s">&#34;Could not write wake signal to fd %d: %s&#34;</span><span class="p">,</span>
                    <span class="n">mWakeEventFd</span><span class="p">,</span> <span class="n">strerror</span><span class="p">(</span><span class="n">errno</span><span class="p">));</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><h4 id="nativepollonce"><code>nativePollOnce</code>:</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-cpp" data-lang="cpp"><span class="kt">void</span> <span class="n">NativeMessageQueue</span><span class="o">::</span><span class="n">pollOnce</span><span class="p">(</span><span class="n">JNIEnv</span><span class="o">*</span> <span class="n">env</span><span class="p">,</span> <span class="n">jobject</span> <span class="n">pollObj</span><span class="p">,</span> <span class="kt">int</span> <span class="n">timeoutMillis</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">mPollEnv</span> <span class="o">=</span> <span class="n">env</span><span class="p">;</span>
    <span class="n">mPollObj</span> <span class="o">=</span> <span class="n">pollObj</span><span class="p">;</span>
    <span class="n">mLooper</span><span class="o">-&gt;</span><span class="n">pollOnce</span><span class="p">(</span><span class="n">timeoutMillis</span><span class="p">);</span>
    <span class="n">mPollObj</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
    <span class="n">mPollEnv</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">mExceptionObj</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">env</span><span class="o">-&gt;</span><span class="n">Throw</span><span class="p">(</span><span class="n">mExceptionObj</span><span class="p">);</span>
        <span class="n">env</span><span class="o">-&gt;</span><span class="n">DeleteLocalRef</span><span class="p">(</span><span class="n">mExceptionObj</span><span class="p">);</span>
        <span class="n">mExceptionObj</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-cpp" data-lang="cpp"><span class="kt">int</span> <span class="n">Looper</span><span class="o">::</span><span class="n">pollOnce</span><span class="p">(</span><span class="kt">int</span> <span class="n">timeoutMillis</span><span class="p">,</span> <span class="kt">int</span><span class="o">*</span> <span class="n">outFd</span><span class="p">,</span> <span class="kt">int</span><span class="o">*</span> <span class="n">outEvents</span><span class="p">,</span> <span class="kt">void</span><span class="o">**</span> <span class="n">outData</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">result</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(;;)</span> <span class="p">{</span>
        <span class="k">while</span> <span class="p">(</span><span class="n">mResponseIndex</span> <span class="o">&lt;</span> <span class="n">mResponses</span><span class="p">.</span><span class="n">size</span><span class="p">())</span> <span class="p">{</span>
            <span class="k">const</span> <span class="n">Response</span><span class="o">&amp;</span> <span class="n">response</span> <span class="o">=</span> <span class="n">mResponses</span><span class="p">.</span><span class="n">itemAt</span><span class="p">(</span><span class="n">mResponseIndex</span><span class="o">++</span><span class="p">);</span>
            <span class="kt">int</span> <span class="n">ident</span> <span class="o">=</span> <span class="n">response</span><span class="p">.</span><span class="n">request</span><span class="p">.</span><span class="n">ident</span><span class="p">;</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">ident</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
                <span class="kt">int</span> <span class="n">fd</span> <span class="o">=</span> <span class="n">response</span><span class="p">.</span><span class="n">request</span><span class="p">.</span><span class="n">fd</span><span class="p">;</span>
                <span class="kt">int</span> <span class="n">events</span> <span class="o">=</span> <span class="n">response</span><span class="p">.</span><span class="n">events</span><span class="p">;</span>
                <span class="kt">void</span><span class="o">*</span> <span class="n">data</span> <span class="o">=</span> <span class="n">response</span><span class="p">.</span><span class="n">request</span><span class="p">.</span><span class="n">data</span><span class="p">;</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">outFd</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="o">*</span><span class="n">outFd</span> <span class="o">=</span> <span class="n">fd</span><span class="p">;</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">outEvents</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="o">*</span><span class="n">outEvents</span> <span class="o">=</span> <span class="n">events</span><span class="p">;</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">outData</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="o">*</span><span class="n">outData</span> <span class="o">=</span> <span class="n">data</span><span class="p">;</span>
                <span class="k">return</span> <span class="n">ident</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>

        <span class="k">if</span> <span class="p">(</span><span class="n">result</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">outFd</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="o">*</span><span class="n">outFd</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">outEvents</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="o">*</span><span class="n">outEvents</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">outData</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="o">*</span><span class="n">outData</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
            <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="n">result</span> <span class="o">=</span> <span class="n">pollInner</span><span class="p">(</span><span class="n">timeoutMillis</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt">  1
</span><span class="lnt">  2
</span><span class="lnt">  3
</span><span class="lnt">  4
</span><span class="lnt">  5
</span><span class="lnt">  6
</span><span class="lnt">  7
</span><span class="lnt">  8
</span><span class="lnt">  9
</span><span class="lnt"> 10
</span><span class="lnt"> 11
</span><span class="lnt"> 12
</span><span class="lnt"> 13
</span><span class="lnt"> 14
</span><span class="lnt"> 15
</span><span class="lnt"> 16
</span><span class="lnt"> 17
</span><span class="lnt"> 18
</span><span class="lnt"> 19
</span><span class="lnt"> 20
</span><span class="lnt"> 21
</span><span class="lnt"> 22
</span><span class="lnt"> 23
</span><span class="lnt"> 24
</span><span class="lnt"> 25
</span><span class="lnt"> 26
</span><span class="lnt"> 27
</span><span class="lnt"> 28
</span><span class="lnt"> 29
</span><span class="lnt"> 30
</span><span class="lnt"> 31
</span><span class="lnt"> 32
</span><span class="lnt"> 33
</span><span class="lnt"> 34
</span><span class="lnt"> 35
</span><span class="lnt"> 36
</span><span class="lnt"> 37
</span><span class="lnt"> 38
</span><span class="lnt"> 39
</span><span class="lnt"> 40
</span><span class="lnt"> 41
</span><span class="lnt"> 42
</span><span class="lnt"> 43
</span><span class="lnt"> 44
</span><span class="lnt"> 45
</span><span class="lnt"> 46
</span><span class="lnt"> 47
</span><span class="lnt"> 48
</span><span class="lnt"> 49
</span><span class="lnt"> 50
</span><span class="lnt"> 51
</span><span class="lnt"> 52
</span><span class="lnt"> 53
</span><span class="lnt"> 54
</span><span class="lnt"> 55
</span><span class="lnt"> 56
</span><span class="lnt"> 57
</span><span class="lnt"> 58
</span><span class="lnt"> 59
</span><span class="lnt"> 60
</span><span class="lnt"> 61
</span><span class="lnt"> 62
</span><span class="lnt"> 63
</span><span class="lnt"> 64
</span><span class="lnt"> 65
</span><span class="lnt"> 66
</span><span class="lnt"> 67
</span><span class="lnt"> 68
</span><span class="lnt"> 69
</span><span class="lnt"> 70
</span><span class="lnt"> 71
</span><span class="lnt"> 72
</span><span class="lnt"> 73
</span><span class="lnt"> 74
</span><span class="lnt"> 75
</span><span class="lnt"> 76
</span><span class="lnt"> 77
</span><span class="lnt"> 78
</span><span class="lnt"> 79
</span><span class="lnt"> 80
</span><span class="lnt"> 81
</span><span class="lnt"> 82
</span><span class="lnt"> 83
</span><span class="lnt"> 84
</span><span class="lnt"> 85
</span><span class="lnt"> 86
</span><span class="lnt"> 87
</span><span class="lnt"> 88
</span><span class="lnt"> 89
</span><span class="lnt"> 90
</span><span class="lnt"> 91
</span><span class="lnt"> 92
</span><span class="lnt"> 93
</span><span class="lnt"> 94
</span><span class="lnt"> 95
</span><span class="lnt"> 96
</span><span class="lnt"> 97
</span><span class="lnt"> 98
</span><span class="lnt"> 99
</span><span class="lnt">100
</span><span class="lnt">101
</span><span class="lnt">102
</span><span class="lnt">103
</span><span class="lnt">104
</span><span class="lnt">105
</span><span class="lnt">106
</span><span class="lnt">107
</span><span class="lnt">108
</span><span class="lnt">109
</span><span class="lnt">110
</span><span class="lnt">111
</span><span class="lnt">112
</span><span class="lnt">113
</span><span class="lnt">114
</span><span class="lnt">115
</span><span class="lnt">116
</span><span class="lnt">117
</span><span class="lnt">118
</span><span class="lnt">119
</span><span class="lnt">120
</span><span class="lnt">121
</span><span class="lnt">122
</span><span class="lnt">123
</span><span class="lnt">124
</span><span class="lnt">125
</span><span class="lnt">126
</span><span class="lnt">127
</span><span class="lnt">128
</span><span class="lnt">129
</span><span class="lnt">130
</span><span class="lnt">131
</span><span class="lnt">132
</span><span class="lnt">133
</span><span class="lnt">134
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-cpp" data-lang="cpp"><span class="kt">int</span> <span class="n">Looper</span><span class="o">::</span><span class="n">pollInner</span><span class="p">(</span><span class="kt">int</span> <span class="n">timeoutMillis</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// Adjust the timeout based on when the next message is due.
</span><span class="c1"></span>    <span class="k">if</span> <span class="p">(</span><span class="n">timeoutMillis</span> <span class="o">!=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">mNextMessageUptime</span> <span class="o">!=</span> <span class="n">LLONG_MAX</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">nsecs_t</span> <span class="n">now</span> <span class="o">=</span> <span class="n">systemTime</span><span class="p">(</span><span class="n">SYSTEM_TIME_MONOTONIC</span><span class="p">);</span>
        <span class="kt">int</span> <span class="n">messageTimeoutMillis</span> <span class="o">=</span> <span class="n">toMillisecondTimeoutDelay</span><span class="p">(</span><span class="n">now</span><span class="p">,</span> <span class="n">mNextMessageUptime</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">messageTimeoutMillis</span> <span class="o">&gt;=</span> <span class="mi">0</span>
                <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="n">timeoutMillis</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="o">||</span> <span class="n">messageTimeoutMillis</span> <span class="o">&lt;</span> <span class="n">timeoutMillis</span><span class="p">))</span> <span class="p">{</span>
            <span class="n">timeoutMillis</span> <span class="o">=</span> <span class="n">messageTimeoutMillis</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="c1">// Poll.
</span><span class="c1"></span>    <span class="kt">int</span> <span class="n">result</span> <span class="o">=</span> <span class="n">POLL_WAKE</span><span class="p">;</span>
    <span class="n">mResponses</span><span class="p">.</span><span class="n">clear</span><span class="p">();</span>
    <span class="n">mResponseIndex</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

    <span class="c1">// We are about to idle.
</span><span class="c1"></span>    <span class="n">mPolling</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>

    <span class="k">struct</span> <span class="nc">epoll_event</span> <span class="n">eventItems</span><span class="p">[</span><span class="n">EPOLL_MAX_EVENTS</span><span class="p">];</span>
    <span class="c1">// 这里重点
</span><span class="c1"></span>    <span class="kt">int</span> <span class="n">eventCount</span> <span class="o">=</span> <span class="n">epoll_wait</span><span class="p">(</span><span class="n">mEpollFd</span><span class="p">,</span> <span class="n">eventItems</span><span class="p">,</span> <span class="n">EPOLL_MAX_EVENTS</span><span class="p">,</span> <span class="n">timeoutMillis</span><span class="p">);</span>

    <span class="c1">// No longer idling.
</span><span class="c1"></span>    <span class="n">mPolling</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>

    <span class="c1">// Acquire lock.
</span><span class="c1"></span>    <span class="n">mLock</span><span class="p">.</span><span class="n">lock</span><span class="p">();</span>

    <span class="c1">// Rebuild epoll set if needed.
</span><span class="c1"></span>    <span class="k">if</span> <span class="p">(</span><span class="n">mEpollRebuildRequired</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">mEpollRebuildRequired</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
        <span class="n">rebuildEpollLocked</span><span class="p">();</span>
        <span class="k">goto</span> <span class="n">Done</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">// Check for poll error.
</span><span class="c1"></span>    <span class="k">if</span> <span class="p">(</span><span class="n">eventCount</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">errno</span> <span class="o">==</span> <span class="n">EINTR</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">goto</span> <span class="n">Done</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="n">ALOGW</span><span class="p">(</span><span class="s">&#34;Poll failed with an unexpected error: %s&#34;</span><span class="p">,</span> <span class="n">strerror</span><span class="p">(</span><span class="n">errno</span><span class="p">));</span>
        <span class="n">result</span> <span class="o">=</span> <span class="n">POLL_ERROR</span><span class="p">;</span>
        <span class="k">goto</span> <span class="n">Done</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">// Check for poll timeout.
</span><span class="c1"></span>    <span class="k">if</span> <span class="p">(</span><span class="n">eventCount</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">result</span> <span class="o">=</span> <span class="n">POLL_TIMEOUT</span><span class="p">;</span>
        <span class="k">goto</span> <span class="n">Done</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">// Handle all events.
</span><span class="c1"></span>    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">eventCount</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">int</span> <span class="n">fd</span> <span class="o">=</span> <span class="n">eventItems</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">data</span><span class="p">.</span><span class="n">fd</span><span class="p">;</span>
        <span class="kt">uint32_t</span> <span class="n">epollEvents</span> <span class="o">=</span> <span class="n">eventItems</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">events</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">fd</span> <span class="o">==</span> <span class="n">mWakeEventFd</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">epollEvents</span> <span class="o">&amp;</span> <span class="n">EPOLLIN</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">awoken</span><span class="p">();</span>
            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                <span class="n">ALOGW</span><span class="p">(</span><span class="s">&#34;Ignoring unexpected epoll events 0x%x on wake event fd.&#34;</span><span class="p">,</span> <span class="n">epollEvents</span><span class="p">);</span>
            <span class="p">}</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="n">ssize_t</span> <span class="n">requestIndex</span> <span class="o">=</span> <span class="n">mRequests</span><span class="p">.</span><span class="n">indexOfKey</span><span class="p">(</span><span class="n">fd</span><span class="p">);</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">requestIndex</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
                <span class="kt">int</span> <span class="n">events</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">epollEvents</span> <span class="o">&amp;</span> <span class="n">EPOLLIN</span><span class="p">)</span> <span class="n">events</span> <span class="o">|=</span> <span class="n">EVENT_INPUT</span><span class="p">;</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">epollEvents</span> <span class="o">&amp;</span> <span class="n">EPOLLOUT</span><span class="p">)</span> <span class="n">events</span> <span class="o">|=</span> <span class="n">EVENT_OUTPUT</span><span class="p">;</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">epollEvents</span> <span class="o">&amp;</span> <span class="n">EPOLLERR</span><span class="p">)</span> <span class="n">events</span> <span class="o">|=</span> <span class="n">EVENT_ERROR</span><span class="p">;</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">epollEvents</span> <span class="o">&amp;</span> <span class="n">EPOLLHUP</span><span class="p">)</span> <span class="n">events</span> <span class="o">|=</span> <span class="n">EVENT_HANGUP</span><span class="p">;</span>
                <span class="n">pushResponse</span><span class="p">(</span><span class="n">events</span><span class="p">,</span> <span class="n">mRequests</span><span class="p">.</span><span class="n">valueAt</span><span class="p">(</span><span class="n">requestIndex</span><span class="p">));</span>
            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                <span class="n">ALOGW</span><span class="p">(</span><span class="s">&#34;Ignoring unexpected epoll events 0x%x on fd %d that is &#34;</span>
                        <span class="s">&#34;no longer registered.&#34;</span><span class="p">,</span> <span class="n">epollEvents</span><span class="p">,</span> <span class="n">fd</span><span class="p">);</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="nl">Done</span><span class="p">:</span> <span class="p">;</span>

    <span class="c1">// Invoke pending message callbacks.
</span><span class="c1"></span>    <span class="n">mNextMessageUptime</span> <span class="o">=</span> <span class="n">LLONG_MAX</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">mMessageEnvelopes</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">nsecs_t</span> <span class="n">now</span> <span class="o">=</span> <span class="n">systemTime</span><span class="p">(</span><span class="n">SYSTEM_TIME_MONOTONIC</span><span class="p">);</span>
        <span class="k">const</span> <span class="n">MessageEnvelope</span><span class="o">&amp;</span> <span class="n">messageEnvelope</span> <span class="o">=</span> <span class="n">mMessageEnvelopes</span><span class="p">.</span><span class="n">itemAt</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">messageEnvelope</span><span class="p">.</span><span class="n">uptime</span> <span class="o">&lt;=</span> <span class="n">now</span><span class="p">)</span> <span class="p">{</span>
            <span class="c1">// Remove the envelope from the list.
</span><span class="c1"></span>            <span class="c1">// We keep a strong reference to the handler until the call to handleMessage
</span><span class="c1"></span>            <span class="c1">// finishes.  Then we drop it so that the handler can be deleted *before*
</span><span class="c1"></span>            <span class="c1">// we reacquire our lock.
</span><span class="c1"></span>            <span class="p">{</span> <span class="c1">// obtain handler
</span><span class="c1"></span>                <span class="n">sp</span><span class="o">&lt;</span><span class="n">MessageHandler</span><span class="o">&gt;</span> <span class="n">handler</span> <span class="o">=</span> <span class="n">messageEnvelope</span><span class="p">.</span><span class="n">handler</span><span class="p">;</span>
                <span class="n">Message</span> <span class="n">message</span> <span class="o">=</span> <span class="n">messageEnvelope</span><span class="p">.</span><span class="n">message</span><span class="p">;</span>
                <span class="n">mMessageEnvelopes</span><span class="p">.</span><span class="n">removeAt</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
                <span class="n">mSendingMessage</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
                <span class="n">mLock</span><span class="p">.</span><span class="n">unlock</span><span class="p">();</span>
                <span class="n">handler</span><span class="o">-&gt;</span><span class="n">handleMessage</span><span class="p">(</span><span class="n">message</span><span class="p">);</span>
            <span class="p">}</span> <span class="c1">// release handler
</span><span class="c1"></span>
            <span class="n">mLock</span><span class="p">.</span><span class="n">lock</span><span class="p">();</span>
            <span class="n">mSendingMessage</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
            <span class="n">result</span> <span class="o">=</span> <span class="n">POLL_CALLBACK</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="c1">// The last message left at the head of the queue determines the next wakeup time.
</span><span class="c1"></span>            <span class="n">mNextMessageUptime</span> <span class="o">=</span> <span class="n">messageEnvelope</span><span class="p">.</span><span class="n">uptime</span><span class="p">;</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="c1">// Release lock.
</span><span class="c1"></span>    <span class="n">mLock</span><span class="p">.</span><span class="n">unlock</span><span class="p">();</span>

    <span class="c1">// Invoke all response callbacks.
</span><span class="c1"></span>    <span class="k">for</span> <span class="p">(</span><span class="n">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">mResponses</span><span class="p">.</span><span class="n">size</span><span class="p">();</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">Response</span><span class="o">&amp;</span> <span class="n">response</span> <span class="o">=</span> <span class="n">mResponses</span><span class="p">.</span><span class="n">editItemAt</span><span class="p">(</span><span class="n">i</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">response</span><span class="p">.</span><span class="n">request</span><span class="p">.</span><span class="n">ident</span> <span class="o">==</span> <span class="n">POLL_CALLBACK</span><span class="p">)</span> <span class="p">{</span>
            <span class="kt">int</span> <span class="n">fd</span> <span class="o">=</span> <span class="n">response</span><span class="p">.</span><span class="n">request</span><span class="p">.</span><span class="n">fd</span><span class="p">;</span>
            <span class="kt">int</span> <span class="n">events</span> <span class="o">=</span> <span class="n">response</span><span class="p">.</span><span class="n">events</span><span class="p">;</span>
            <span class="kt">void</span><span class="o">*</span> <span class="n">data</span> <span class="o">=</span> <span class="n">response</span><span class="p">.</span><span class="n">request</span><span class="p">.</span><span class="n">data</span><span class="p">;</span>
            <span class="c1">// Invoke the callback.  Note that the file descriptor may be closed by
</span><span class="c1"></span>            <span class="c1">// the callback (and potentially even reused) before the function returns so
</span><span class="c1"></span>            <span class="c1">// we need to be a little careful when removing the file descriptor afterwards.
</span><span class="c1"></span>            <span class="kt">int</span> <span class="n">callbackResult</span> <span class="o">=</span> <span class="n">response</span><span class="p">.</span><span class="n">request</span><span class="p">.</span><span class="n">callback</span><span class="o">-&gt;</span><span class="n">handleEvent</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">events</span><span class="p">,</span> <span class="n">data</span><span class="p">);</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">callbackResult</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">removeFd</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">response</span><span class="p">.</span><span class="n">request</span><span class="p">.</span><span class="n">seq</span><span class="p">);</span>
            <span class="p">}</span>

            <span class="c1">// Clear the callback reference in the response structure promptly because we
</span><span class="c1"></span>            <span class="c1">// will not clear the response vector itself until the next poll.
</span><span class="c1"></span>            <span class="n">response</span><span class="p">.</span><span class="n">request</span><span class="p">.</span><span class="n">callback</span><span class="p">.</span><span class="n">clear</span><span class="p">();</span>
            <span class="n">result</span> <span class="o">=</span> <span class="n">POLL_CALLBACK</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></td></tr></table>
</div>
</div>
    </article>
    
    <script>
  'use strict';
  
  function wrap(el, wrapper) {
    el.parentNode.insertBefore(wrapper, el);
    wrapper.appendChild(el);
  }

  (function () {
    var singleContentsElem = document.querySelector('.single__contents');
    singleContentsElem ? 
    singleContentsElem.querySelectorAll('pre > code').forEach(function(elem) {
      var dataLang = elem.getAttribute('data-lang');
      var dataLangWrapper = document.createElement('div');
      var code = null;
      var codeTitle = null;

      if (dataLang && dataLang.includes(':')) {
        code = dataLang.split(':')[0];
        codeTitle = dataLang.split(':')[1];

        dataLangWrapper.className = 'language-' + code;
        dataLangWrapper.setAttribute('data-lang', codeTitle);

        elem.className = 'language-' + code;
        elem.setAttribute('data-lang', codeTitle);
        elem.setAttribute('id', codeTitle);
      } else if (!dataLang) {
        dataLangWrapper.setAttribute('data-lang', 'Code');
        dataLangWrapper.className = 'language-code';
      }

      if (!dataLang || codeTitle) {
        wrap(elem.parentNode, dataLangWrapper);
      }

    }) : null;
  })();

  var langCodeElem = document.querySelectorAll('.language-code');
  langCodeElem ? langCodeElem.forEach(function (elem) {
    var newElem = document.createElement('span');
    newElem.className = 'copy-to-clipboard';
    newElem.setAttribute('title', 'Copy to clipboard');
    elem.append(newElem);
  }) : null;
  
</script>
    
    
    
<div class="whoami__gutter"></div>
<hr class="hr-slash whoami-hr"/>
<section class="whoami">
  <div class="whoami__image-wrapper">
    
    
      
        <img data-src="/images/whoami/avatar.jpg" src="data:image/svg+xml,%0A%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath fill='none' d='M0 0h24v24H0V0z'/%3E%3Cpath fill='%23aaa' d='M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-1 16H6c-.55 0-1-.45-1-1V6c0-.55.45-1 1-1h12c.55 0 1 .45 1 1v12c0 .55-.45 1-1 1zm-4.44-6.19l-2.35 3.02-1.56-1.88c-.2-.25-.58-.24-.78.01l-1.74 2.23c-.26.33-.02.81.39.81h8.98c.41 0 .65-.47.4-.8l-2.55-3.39c-.19-.26-.59-.26-.79 0z'/%3E%3C/svg%3E" alt="Yang" class="lazyload whoami__image"/>
      
    
  </div>
  <div class="whoami__contents">
    <div class="whoami__written-by">
      WRITTEN BY
    </div>
    <div class="whoami__title">
      
        Yang
      
    </div>
    <div class="whoami__desc">
      
        Developer
      
    </div>
    <div class="whoami__social">
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      <a href="https://github.com/stefanji" title="github" aria-label="github">
        <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="25" height="25" viewBox="0 0 24 24" version="1.1">
<g id="surface3680">
<path fill="currentColor" d="M 10.898438 2.101562 C 6.300781 2.601562 2.601562 6.300781 2.101562 10.800781 C 1.601562 15.5 4.300781 19.699219 8.398438 21.300781 C 8.699219 21.398438 9 21.199219 9 20.800781 L 9 19.199219 C 9 19.199219 8.601562 19.300781 8.101562 19.300781 C 6.699219 19.300781 6.101562 18.101562 6 17.398438 C 5.898438 17 5.699219 16.699219 5.398438 16.398438 C 5.101562 16.300781 5 16.300781 5 16.199219 C 5 16 5.300781 16 5.398438 16 C 6 16 6.5 16.699219 6.699219 17 C 7.199219 17.800781 7.800781 18 8.101562 18 C 8.5 18 8.800781 17.898438 9 17.800781 C 9.101562 17.101562 9.398438 16.398438 10 16 C 7.699219 15.5 6 14.199219 6 12 C 6 10.898438 6.5 9.800781 7.199219 9 C 7.101562 8.800781 7 8.300781 7 7.601562 C 7 7.199219 7 6.601562 7.300781 6 C 7.300781 6 8.699219 6 10.101562 7.300781 C 10.601562 7.101562 11.300781 7 12 7 C 12.699219 7 13.398438 7.101562 14 7.300781 C 15.300781 6 16.800781 6 16.800781 6 C 17 6.601562 17 7.199219 17 7.601562 C 17 8.398438 16.898438 8.800781 16.800781 9 C 17.5 9.800781 18 10.800781 18 12 C 18 14.199219 16.300781 15.5 14 16 C 14.601562 16.5 15 17.398438 15 18.300781 L 15 20.898438 C 15 21.199219 15.300781 21.5 15.699219 21.398438 C 19.398438 19.898438 22 16.300781 22 12.101562 C 22 6.101562 16.898438 1.398438 10.898438 2.101562 Z M 10.898438 2.101562 "/>
</g>
</svg>

      </a>
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    </div>
  </div>
</section>
<hr class="hr-slash whoami-hr" />


    <section class="related">
    
    
  </section>
    <div class="grow"></div>
<nav class="pagination-single">
  
    
      <a href="https://blog.jiyang.site/posts/2019-10-18-objectoutputstream-%E4%BD%BF%E7%94%A8%E4%BC%98%E5%8C%96/" class="pagination-single__left">
        <div class="pagination-single__icon">
          <svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path fill="currentColor" d="M19 11H7.83l4.88-4.88c.39-.39.39-1.03 0-1.42-.39-.39-1.02-.39-1.41 0l-6.59 6.59c-.39.39-.39 1.02 0 1.41l6.59 6.59c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41L7.83 13H19c.55 0 1-.45 1-1s-.45-1-1-1z"/></svg>
        </div>
        <div class="pagination-single__left-title">优化 ObjectOutputStream 的使用</div>      
      </a>
    
    <div class="grow"></div>
    
      <a href="https://blog.jiyang.site/posts/2019-10-20-flutter-%E5%9C%A8-android-%E4%B8%8A%E6%98%AF%E5%A6%82%E4%BD%95%E8%BF%90%E8%A1%8C%E8%B5%B7%E6%9D%A5%E7%9A%84/" class="pagination-single__right">      
        <div class="pagination-single__right-title">Flutter 在 Android 上是如何运行起来的</div>
        <div class="pagination-single__icon">
          <svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path fill="currentColor" d="M5 13h11.17l-4.88 4.88c-.39.39-.39 1.03 0 1.42.39.39 1.02.39 1.41 0l6.59-6.59c.39-.39.39-1.02 0-1.41l-6.58-6.6c-.39-.39-1.02-.39-1.41 0-.39.39-.39 1.02 0 1.41L16.17 11H5c-.55 0-1 .45-1 1s.45 1 1 1z"/></svg>
        </div>
      </a>
    
  
</nav>
    
  
    <div id="gitalk-container"></div>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.css" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.min.js" crossorigin="anonymous"></script>
<script>
  var gitalk = new Gitalk({
    id: '2019-10-19 20:53:02 \u002b0000 UTC',
    title: 'Android 中 MessageQueue 的 nativePollOnce',
    clientID: '93599b11da5a176286c4',
    clientSecret: 'd50fe6b681662b8a96bd9c00efe718d17da286ad',
    repo: 'stefanji.github.io',
    owner: 'stefanji',
    admin: ['stefanji'],
    body: decodeURI(location.href)
  });
  gitalk.render('gitalk-container');
</script>
<noscript>Please enable JavaScript to view the <a href="https://github.com/gitalk/gitalk">comments powered by gitalk.</a></noscript>
  

    <div class="modal micromodal-slide" id="modal" aria-hidden="true">
  <div class="modal__overlay" tabindex="-1" data-micromodal-close>
    <div class="modal__container" role="dialog" aria-modal="true" aria-labelledby="modal-title">
      
      <div class="modal__content" id="modal-content">
        <div id="mySwipe" class="swipe">
          <div class="swipe-wrap">
          </div>
        </div>
      </div>

      <span class="modal__items">
        
        <span class="modal__header">
          <div class="modal__paging" title="Page Info" aria-label="Current Page">
          </div>
          <div class="modal__icon modal__toolbar modal__toolbar--close" title="Close" aria-label="Close Button" data-micromodal-close>
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26" width="25" height="25"><path fill="currentColor" d="M 21.734375 19.640625 L 19.636719 21.734375 C 19.253906 22.121094 18.628906 22.121094 18.242188 21.734375 L 13 16.496094 L 7.761719 21.734375 C 7.375 22.121094 6.746094 22.121094 6.363281 21.734375 L 4.265625 19.640625 C 3.878906 19.253906 3.878906 18.628906 4.265625 18.242188 L 9.503906 13 L 4.265625 7.761719 C 3.882813 7.371094 3.882813 6.742188 4.265625 6.363281 L 6.363281 4.265625 C 6.746094 3.878906 7.375 3.878906 7.761719 4.265625 L 13 9.507813 L 18.242188 4.265625 C 18.628906 3.878906 19.257813 3.878906 19.636719 4.265625 L 21.734375 6.359375 C 22.121094 6.746094 22.121094 7.375 21.738281 7.761719 L 16.496094 13 L 21.734375 18.242188 C 22.121094 18.628906 22.121094 19.253906 21.734375 19.640625 Z"/></svg>
          </div>
          <div class="modal__icon modal__toolbar modal__toolbar--full" title="Full Screen" aria-label="Full Screen Button">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="25" height="25"><path fill="currentColor" d="M 5 3 C 3.9069372 3 3 3.9069372 3 5 L 3 8 A 1.0001 1.0001 0 1 0 5 8 L 5 5 L 8 5 A 1.0001 1.0001 0 1 0 8 3 L 5 3 z M 16 3 A 1.0001 1.0001 0 1 0 16 5 L 19 5 L 19 8 A 1.0001 1.0001 0 1 0 21 8 L 21 5 C 21 3.9069372 20.093063 3 19 3 L 16 3 z M 3.984375 14.986328 A 1.0001 1.0001 0 0 0 3 16 L 3 19 C 3 20.093063 3.9069372 21 5 21 L 8 21 A 1.0001 1.0001 0 1 0 8 19 L 5 19 L 5 16 A 1.0001 1.0001 0 0 0 3.984375 14.986328 z M 19.984375 14.986328 A 1.0001 1.0001 0 0 0 19 16 L 19 19 L 16 19 A 1.0001 1.0001 0 1 0 16 21 L 19 21 C 20.093063 21 21 20.093063 21 19 L 21 16 A 1.0001 1.0001 0 0 0 19.984375 14.986328 z"/></svg>
          </div>
          <div class="modal__icon modal__toolbar modal__toolbar--normal" title="Normal Screen" aria-label="Normal Screen Button">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" width="25" height="25"><path fill="currentColor" d="M 16.96875 4.972656 C 15.867188 4.988281 14.984375 5.894531 15 7 L 15 15 L 7 15 C 6.277344 14.988281 5.609375 15.367188 5.246094 15.992188 C 4.878906 16.613281 4.878906 17.386719 5.246094 18.007813 C 5.609375 18.632813 6.277344 19.011719 7 19 L 19 19 L 19 7 C 19.007813 6.460938 18.796875 5.941406 18.414063 5.558594 C 18.03125 5.175781 17.511719 4.964844 16.96875 4.972656 Z M 32.96875 4.972656 C 31.921875 4.988281 31.0625 5.8125 31.003906 6.859375 C 31 6.90625 31 6.953125 31 7 L 31 19 L 43 19 C 43.066406 19 43.132813 19 43.199219 18.992188 C 44.269531 18.894531 45.070313 17.972656 45.015625 16.902344 C 44.964844 15.828125 44.074219 14.988281 43 15 L 35 15 L 35 7 C 35.007813 6.460938 34.796875 5.941406 34.414063 5.558594 C 34.03125 5.175781 33.511719 4.964844 32.96875 4.972656 Z M 7 31 C 6.277344 30.988281 5.609375 31.367188 5.246094 31.992188 C 4.878906 32.613281 4.878906 33.386719 5.246094 34.007813 C 5.609375 34.632813 6.277344 35.011719 7 35 L 15 35 L 15 43 C 14.988281 43.722656 15.367188 44.390625 15.992188 44.753906 C 16.613281 45.121094 17.386719 45.121094 18.007813 44.753906 C 18.632813 44.390625 19.011719 43.722656 19 43 L 19 31 Z M 31 31 L 31 43 C 30.988281 43.722656 31.367188 44.390625 31.992188 44.753906 C 32.613281 45.121094 33.386719 45.121094 34.007813 44.753906 C 34.632813 44.390625 35.011719 43.722656 35 43 L 35 35 L 43 35 C 43.722656 35.011719 44.390625 34.632813 44.753906 34.007813 C 45.121094 33.386719 45.121094 32.613281 44.753906 31.992188 C 44.390625 31.367188 43.722656 30.988281 43 31 Z"/></svg>
          </div>
        </span>
        
        <div class="modal__icon modal__arrow modal__arrow--left" title="Arrow Left" aria-label="Arrow Left Button">
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26" width="28" height="28"><path fill="currentColor" d="M 23.28125 11 L 10 10 L 10 6.851563 C 10 6.523438 9.839844 6.277344 9.519531 6.03125 C 9.199219 5.949219 8.878906 5.949219 8.640625 6.113281 C 5.359375 8.410156 2.238281 12.257813 2.160156 12.421875 C 2.082031 12.578125 2.007813 12.8125 2.003906 12.976563 C 2.003906 12.980469 2 12.988281 2 12.992188 C 2 13.15625 2.078125 13.402344 2.160156 13.484375 C 2.238281 13.648438 5.28125 17.507813 8.640625 19.804688 C 8.960938 19.96875 9.28125 20.050781 9.519531 19.886719 C 9.839844 19.722656 10 19.476563 10 19.148438 L 10 16 L 23.28125 15 C 23.679688 14.679688 24 13.875 24 12.992188 C 24 12.195313 23.761719 11.320313 23.28125 11 Z"/></svg>
        </div>
        
        <div class="modal__icon modal__arrow modal__arrow--right" title="Arrow Right" aria-label="Arrow Right Button">

          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26" width="28" height="28"><path fill="currentColor" d="M 2.71875 11.023438 L 16 10.023438 L 16 6.875 C 16 6.546875 16.160156 6.300781 16.480469 6.054688 C 16.800781 5.972656 17.121094 5.972656 17.359375 6.136719 C 20.640625 8.433594 23.761719 12.28125 23.839844 12.445313 C 23.917969 12.601563 23.992188 12.835938 23.996094 13 C 23.996094 13.003906 24 13.011719 24 13.015625 C 24 13.179688 23.921875 13.425781 23.839844 13.507813 C 23.761719 13.671875 20.71875 17.53125 17.359375 19.828125 C 17.039063 19.992188 16.71875 20.074219 16.480469 19.910156 C 16.160156 19.746094 16 19.5 16 19.171875 L 16 16.023438 L 2.71875 15.023438 C 2.320313 14.703125 2 13.898438 2 13.015625 C 2 12.21875 2.238281 11.34375 2.71875 11.023438 Z"/></svg>
        </div>

        <div class="modal__caption">
          <div class="modal__caption--text">
          </div>
        </div>

      </span>
    </div>
  </div>
</div>


<script defer src="/js/swipe.min.08ff2be1b74347bad9e267f732f1388d271b2f9d97b6a8a87bd6a510f17c5ad2.js"></script>

<script defer src="/js/micromodal.min.de01b44b2f383056bbcaf6ee921fd385d79108ec1129afd0eb2f3f5a07e11f45.js"></script>

<script defer src="/js/helper/fadeinout.min.js"></script>

<script>
document.addEventListener('DOMContentLoaded', function () {
  
   
  var docElem = document.documentElement;

   
  function openFullscreen() {
    if (docElem.requestFullscreen) {
      docElem.requestFullscreen();
    } else if (docElem.mozRequestFullScreen) {  
      docElem.mozRequestFullScreen();
    } else if (docElem.webkitRequestFullscreen) {  
      docElem.webkitRequestFullscreen();
    } else if (docElem.msRequestFullscreen) {  
      docElem.msRequestFullscreen();
    }
  }

   
  function closeFullscreen() {
    if (document.fullscreenElement ||
      document.webkitFullscreenElement ||
      document.mozFullScreenElement) {
      if (document.exitFullscreen) {
        document.exitFullscreen();
      } else if (document.mozCancelFullScreen) {  
        document.mozCancelFullScreen();
      } else if (document.webkitExitFullscreen) {  
        document.webkitExitFullscreen();
      } else if (document.msExitFullscreen) {  
        document.msExitFullscreen();
      }
    }
  }

  var modal = document.getElementById('modal');
  var galleryContainerElem = document.querySelector('.gallery__container');
  var swipeWrapElem = document.querySelector('.swipe-wrap');
  var mySwipeElem = document.getElementById('mySwipe');
  var arrowLeftElem = document.querySelector('.modal__arrow--left');
  var arrowRightElem = document.querySelector('.modal__arrow--right');
  var closeElem = document.querySelector('.modal__toolbar--close');
  var fullElem = document.querySelector('.modal__toolbar--full');
  var normalElem = document.querySelector('.modal__toolbar--normal');
  var captionElem = document.querySelector('.modal__caption');
  var pagingElem = document.querySelector('.modal__paging');
  var itemsElem = document.querySelector('.modal__items');
  var imgTotalNum = null;
  var myFadeTimeout = null;
  var mySwipe = null;
  var keydownFunction = function (e) {
    if (e.key === 'ArrowRight') {
      if (modal && modal.classList.contains('is-open')) {
        mySwipe.next();
      }
    } else if (e.key === 'ArrowLeft') {
      if (modal && modal.classList.contains('is-open')) {
        mySwipe.prev();
      }
    }
  }

  if (galleryContainerElem) {
    imgTotalNum = galleryContainerElem.querySelectorAll('img').length;
  } else {
    galleryContainerElem = document.querySelector('.single__contents');
    imgTotalNum = galleryContainerElem.querySelectorAll('img').length;
  }

  MicroModal.init({
    onClose: function () {
      if (mySwipe) {
        mySwipe.kill();
        mySwipe = null;
        closeFullscreen();
      }
      window.removeEventListener('keydown', keydownFunction);
    },
    disableScroll: true,
    disableFocus: true,
    awaitOpenAnimation: false,
    awaitCloseAnimation: false,
    debugMode: false,
  });

  var imageLoad = function(src) {
    return new Promise(function(resolve, reject) {
      var newImg = new Image;
      newImg.onload = function() {
        resolve(newImg);
      }
      newImg.onerror = reject;
      newImg.src = src;
    });
  }

  galleryContainerElem.querySelectorAll('img').forEach(function (elem, idx) {
    elem.style.cursor = 'pointer';

    var clonedElem = elem.cloneNode(true);
    clonedElem.style.maxHeight = '100%';
    clonedElem.style.maxWidth = '100%';
    clonedElem.onclick = function (e) {
      e.stopPropagation();
    }

    var wrapper = document.createElement('div');
    wrapper.style.width = '100%';
    wrapper.style.height = '100vh';
    wrapper.setAttribute('data-micromodal-close', '');
    wrapper.onclick = function () {
      if (mySwipe) {
        mySwipe.kill();
        mySwipe = null;
      }
    }
    wrapper.onmouseenter = function () {
      clearTimeout(myFadeTimeout);
      fadeIn(itemsElem, 200);
    };
    wrapper.onmouseleave = function () {
      myFadeTimeout = setTimeout(function () {
        fadeOut(itemsElem, 200);
      }, 2500);
    }
    wrapper.ontouchstart = function() {
      fadeIn(itemsElem, 200);
    }
    wrapper.append(clonedElem);
    swipeWrapElem.append(wrapper);

    elem.addEventListener('click', async function (e) {
      MicroModal.show('modal');
      if (mySwipe) {
        mySwipe.kill();
        mySwipe = null;
      }

      var imgSrc = e.target.getAttribute('data-src') || e.target.getAttribute('src');
      var img = await imageLoad(imgSrc);
      clonedElem.style.width = img.width + 'px';
      clonedElem.style.height = img.height + 'px';
      
      
      mySwipe = new Swipe(mySwipeElem, {
        startSlide: idx,
        draggable: true,
        autoRestart: false,
        continuous: false,
        disableScroll: true,
        stopPropagation: true,
        callback: async function (index, element) {
          
          var imgElem = element.querySelector('img');
          var imgSrc = imgElem.getAttribute('data-src') || imgElem.getAttribute('src');
          var img = await imageLoad(imgSrc);
          imgElem.style.width = img.width + 'px';
          imgElem.style.height = img.height + 'px';

          
          if (captionElem && imgElem) {
            var caption = null;
            if (imgElem.getAttribute('data-caption')) {
              caption = imgElem.getAttribute('data-caption');
            } else if (imgElem.getAttribute('title')) {
              caption = imgElem.getAttribute('title');
            } else if (imgElem.getAttribute('alt')) {
              caption = imgElem.getAttribute('alt');
            } else {
              caption = imgElem.getAttribute('src');
            }

            captionElem.querySelector('.modal__caption--text').innerText = caption;
            pagingElem.innerText = (index + 1) + ' / ' + imgTotalNum;

            clearTimeout(myFadeTimeout);
            fadeIn(itemsElem, 200);
          }
        },
      });

      fadeIn(itemsElem);

      
      if (captionElem) {
        var caption = null;
        if (e.target.getAttribute('data-caption')) {
          caption = e.target.getAttribute('data-caption');
        } else if (e.target.getAttribute('title')) {
          caption = e.target.getAttribute('title');
        } else if (e.target.getAttribute('alt')) {
          caption = e.target.getAttribute('alt');
        } else {
          caption = e.target.getAttribute('src');
        }

        captionElem.querySelector('.modal__caption--text').innerText = caption;
        pagingElem.innerText = (idx + 1) + ' / ' + imgTotalNum;
      }

      if (normalElem && fullElem) {
        normalElem.style.zIndex = -1;
        normalElem.style.opacity = 0;
        fullElem.style.zIndex = 25;
        fullElem.style.opacity = 1;
      }
    });

    window.addEventListener('keydown', keydownFunction);
  });

  arrowLeftElem ?
    arrowLeftElem.addEventListener('click', function (e) {
      if (mySwipe) {
        mySwipe.prev();
      }
    }) : null;
  arrowRightElem ?
    arrowRightElem.addEventListener('click', function (e) {
      if (mySwipe) {
        mySwipe.next();
      }
    }) : null;

  closeElem ?
    closeElem.addEventListener('click', function () {
      if (mySwipe) {
        mySwipe.kill();
        mySwipe = null;
      }
      closeFullscreen();
      MicroModal.close('modal');
    }) : null;

  fullElem ?
    fullElem.addEventListener('click', function (e) {
      openFullscreen();
      if (normalElem) {
        normalElem.style.zIndex = 25;
        normalElem.style.opacity = 1;
        fullElem.style.zIndex = -1;
        fullElem.style.opacity = 0;
      }
    }) : null;

  normalElem ?
    normalElem.addEventListener('click', function (e) {
      closeFullscreen();
      if (fullElem) {
        fullElem.style.zIndex = 25;
        fullElem.style.opacity = 1;
        normalElem.style.zIndex = -1;
        normalElem.style.opacity = 0;
      }
    }) : null;
  
});
</script>

    <div class="hide">
      

<div class="search">
  <span class="icon">
    <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" fill="currentColor" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M15.5 14h-.79l-.28-.27c1.2-1.4 1.82-3.31 1.48-5.34-.47-2.78-2.79-5-5.59-5.34-4.23-.52-7.79 3.04-7.27 7.27.34 2.8 2.56 5.12 5.34 5.59 2.03.34 3.94-.28 5.34-1.48l.27.28v.79l4.25 4.25c.41.41 1.08.41 1.49 0 .41-.41.41-1.08 0-1.49L15.5 14zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/></svg>
  </span>
  <input id="search" aria-label="Site Search" class="input" type="text" placeholder="Search" autocomplete="off">
  <div id="search-results" class="dropdown">
    <div id="search-menu" class="dropdown-menu" role="menu">
    </div>
  </div>
</div>


    </div>
  </div>
</main>


<aside class="single__side main-side">
  


<section class="sidebar hide">
  <script>document.querySelector('.sidebar').classList.remove('hide')</script>
  <div class="toc__flexbox" data-position="fixed">
    <h6 class="toc__title" data-ani="true">What&#39;s on this Page</h6>
    
      <label class="switch" data-ani="true">
        <input id="toggle-toc" aria-label="Toggle TOC" type="checkbox" checked>
        <span class="slider round"></span>
      </label>
    
  </div>
  <div class="toc " data-dir="ltr" data-folding="false" data-ani="true">
    <nav id="TableOfContents">
  <ul>
    <li>
      <ul>
        <li><a href="#来自高手的解释">来自高手的解释</a></li>
        <li><a href="#我以前的理解分享">我以前的理解分享</a></li>
        <li><a href="#看下源码">看下源码</a>
          <ul>
            <li><a href="#java-这边">Java 这边</a>
              <ul>
                <li><a href="#enqueuemessage"><code>enqueueMessage</code>:</a></li>
                <li><a href="#next"><code>next</code>:</a></li>
              </ul>
            </li>
            <li><a href="#cpp-那边">CPP 那边</a>
              <ul>
                <li><a href="#nativewake"><code>nativeWake</code></a></li>
                <li><a href="#nativepollonce"><code>nativePollOnce</code>:</a></li>
              </ul>
            </li>
          </ul>
        </li>
      </ul>
    </li>
  </ul>
</nav>
  </div>
</section>



</aside>

<script>
  
  
  

  var enableToc = JSON.parse("true");
  var toc = JSON.parse("null");
  var tocPosition = JSON.parse("\"inner\"");
  
  var singleMainElem = document.querySelector('.single__main');
  var singleSideElem = document.querySelector('.single__side');

  enquire.register("screen and (max-width: 769px)", {
    match: function () {
      if ((enableToc || toc) && tocPosition !== "outer") {
        if (singleMainElem && singleSideElem) {
          singleMainElem.classList.remove('main-main');
          singleMainElem.classList.add('main');
          singleSideElem.classList.remove('main-side');
          singleSideElem.classList.add('hide');
        }
      } else if (tocPosition === "outer") {
        if (singleMainElem && !singleMainElem.classList.contains('main-main')) {
          singleMainElem.classList.remove('main-main');
          singleMainElem.classList.add('main');
        }
        if (singleSideElem && !singleSideElem.classList.contains('hide')) {
          singleSideElem.classList.add('hide');
        }
      }
    },
    unmatch: function () {
      if ((enableToc || toc) && tocPosition !== "outer") {
        singleMainElem.classList.remove('main');
        singleMainElem.classList.add('main-main');
        singleSideElem.classList.remove('hide');
        singleSideElem.classList.add('main-side');
      } else if (tocPosition === "outer") {
        if (singleMainElem && !singleMainElem.classList.contains('main-main')) {
          singleMainElem.classList.remove('main-main');
          singleMainElem.classList.add('main');
        }
        if (singleSideElem && !singleSideElem.classList.contains('hide')) {
          singleSideElem.classList.add('hide');
        }
      }

      var navCollapseBtn = document.querySelector('.navbar__burger');
      var navCollapse = document.getElementsByClassName('navbarm__collapse')[0];
      if (navCollapse) {
        navCollapse.setAttribute('data-open', false);
        navCollapse.style.maxHeight = 0;
        navCollapseBtn.classList.remove('is-active');
      }
      document.getElementsByClassName('navbar__menu')[0].classList.remove('is-active');
      document.getElementsByClassName('mobile-search')[0].classList.add('hide');
    },
    setup: function () { },
    deferSetup: true,
    destroy: function () { },
  });
</script>




<script defer src="/js/clipboard.min.1626706afc88d95ebe1173b553ec732c6dc82a576989315fdf5e7779af738a44.js"></script>

<script defer src="/js/helper/getParents.min.js"></script>

<script defer src="/js/helper/closest.min.js"></script>

<script defer src="/js/helper/prev.min.js"></script>

<script defer src="/js/helper/prop.min.js"></script>

<script defer src="/js/helper/fadeinout.min.js"></script>

















<script>
  'use strict';

  window.onload = function() {
    var navbar = document.querySelector('.navbar');
    var singleContentsElem = document.querySelector('.single__contents');

    
    
    
    var enableBusuanzi = JSON.parse("false");
    var busuanziPagePV = JSON.parse("true");
    
    if (enableBusuanzi && busuanziPagePV) {
      var pagePvElem = document.querySelector('#busuanzi_value_page_pv');
      pagePvElem.textContent = pagePvElem.textContent.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");
    }    
    


    
    
    
    
    
    
    var enableToc = JSON.parse("true");
    var toc = JSON.parse("null");
    var hideToc = JSON.parse("false");
    var tocFlexbox = document.querySelector('.toc__flexbox');
    var tocFlexboxOuter = document.querySelector('.toc__flexbox--outer');
    var tocFolding = JSON.parse("false");
    
    if ((enableToc || toc) && document.querySelector('.toc')) {
      var tableOfContentsElem = document.querySelector('.toc').querySelector('#TableOfContents');

      if (false === tocFolding) {

      } else {
        tableOfContentsElem.querySelectorAll('ul') ?
          tableOfContentsElem.querySelectorAll('ul').forEach(function (rootUl) {
            rootUl.querySelectorAll('li').forEach(function (liElem) {
              liElem.querySelectorAll('ul').forEach(function (ulElem) {
                ulElem.style.display = 'none';
              });
            });
          }) : null;
      }

      if (tableOfContentsElem) {
        if (tableOfContentsElem.querySelectorAll('a').length > 0) {
          tableOfContentsElem.querySelectorAll('a').forEach(function (elem) {
            elem.addEventListener('click', function () {
              var id = elem.getAttribute('id');
              navbar.classList.remove('navbar--show');
              navbar.classList.remove('navbar--hide');
              navbar.classList.add('navbar--hide');

              document.querySelector('.toc').querySelectorAll('a').forEach(function (elem) {
                elem.classList.remove('active');
              });
              elem.classList.add('active');

              var curElem = tableOfContentsElem.querySelector('[href="#' + id + '"]');
              if (curElem && curElem.nextElementSibling) {
                curElem.nextElementSibling.style.display = 'block';
              }
              if (curElem) {
                getParents(curElem, 'ul') ?
                  getParents(curElem, 'ul').forEach(function (elem) {
                    elem.style.display = 'block';
                  }) : null;
              }
            });
          });
        } else {
          if (tocFlexbox) {
            tocFlexbox.setAttribute('data-position', '');
            if (!tocFlexbox.classList.contains('hide')) {
              tocFlexbox.classList.add('hide');
            }
          }
          if (tocFlexboxOuter) {
            tocFlexboxOuter.setAttribute('data-position', '');
            if (!tocFlexboxOuter.classList.contains('hide')) {
              tocFlexboxOuter.classList.add('hide');
            }
          }
        }
      }

      
      var toggleTocElem = document.getElementById("toggle-toc");
      var visibleTocElem = document.getElementById('visible-toc');
      var tocElem = document.querySelector('.toc');
      var mainElem = document.querySelector('main');
      var sideElem = document.querySelector('side');
      var tocFlexboxElem = document.querySelector('.toc__flexbox');

      toggleTocElem ? 
      toggleTocElem.addEventListener('change', function(e) {
        if (e.target.checked) {
          if (tocElem) {
            fadeIn(tocElem, 200);
          }
          if (tocFlexboxElem) {
            tocFlexboxElem.setAttribute('data-position', 'fixed');
          }

          if (mainElem) {
            mainElem.classList.remove('main-main');
            mainElem.classList.remove('main');
            mainElem.classList.add('main-main');
          }
          if (sideElem) {
            sideElem.classList.remove('main-side');
          }
        } else {
          if (tocElem) {
            fadeOut(tocElem, 200);
          }
          if (tocFlexboxElem) {
            tocFlexboxElem.setAttribute('data-position', 'absolute');
          }

          if (mainElem) {
            mainElem.classList.remove('main-main');
            mainElem.classList.remove('main');
            mainElem.classList.add('main');
          }
          if (sideElem) {
            sideElem.classList.remove('main-side');
          }
        }
      }) : null;

      visibleTocElem ?
      visibleTocElem.addEventListener('change', function(e) {
        if (e.target.checked) {
          if (tocElem) {
            fadeIn(tocElem, 200);
          }
        } else {
          if (tocElem) {
            fadeOut(tocElem, 200);
          }
        }
      }) : null;
    }
    


    
    var tables = document.querySelectorAll('.single__contents > table');
    for (let i = 0; i < tables.length; i++) {
      var table = tables[i];
      var wrapper = document.createElement('div');
      wrapper.className = 'table-wrapper';
      table.parentElement.replaceChild(wrapper, table);
      wrapper.appendChild(table);
    }
    


    
    var text, clip = new ClipboardJS('.anchor');
    var headers = singleContentsElem.querySelectorAll("h1, h2, h3, h4");

    
    var languagedir = JSON.parse("\"ltr\"");

    headers ? 
    headers.forEach(function (elem) {
      var url = encodeURI(document.location.origin + document.location.pathname);
      var link = url + "#" + elem.getAttribute('id');
      var newElemOuter = document.createElement('span');
      newElemOuter.classList.add('anchor');
      newElemOuter.classList.add('hide');
      newElemOuter.setAttribute('data-clipboard-text', link);
      newElemOuter.style.position = 'relative';

      var newElemInner = document.createElement('span');
      newElemInner.style.fontSize = '1rem';
      newElemInner.style.position = 'absolute';
      newElemInner.style.top = '50%';
      newElemInner.style.transform = 'translateY(-50%)';
      newElemInner.innerText = "🔗";

      if (languagedir === "rtl") {
        newElemInner.style.left = '-2rem';
      } else {
        newElemInner.style.right = '-2rem';
      }

      newElemOuter.append(newElemInner);
      elem.append(newElemOuter);

      elem.addEventListener('mouseenter', function() {
        this.querySelector('.anchor').classList.remove('hide');
      });
      elem.addEventListener('mouseleave', function () {
        this.querySelector('.anchor').classList.add('hide');
      });
    }) : null;

    document.querySelectorAll('.anchor').forEach(function(elem) {
      elem.addEventListener('mouseleave', function() {
        elem.setAttribute('aria-label', null);
        elem.classList.remove('tooltipped');
        elem.classList.remove('tooltipped-s');
        elem.classList.remove('tooltipped-w');
      });
    });

    clip.on('success', function (e) {
      e.clearSelection();
      e.trigger.setAttribute('aria-label', 'Link copied to clipboard!');
      e.trigger.classList.add('tooltipped');
      e.trigger.classList.add('tooltipped-s');
    });
    


    
    var clipInit = false;
    var preChromaElem = document.querySelectorAll('pre.chroma');
    var langCodeElem = document.querySelectorAll('.language-code');
    var dollarCodeElem = document.querySelectorAll('div.language-\\$');
    var gtCodeElem = document.querySelectorAll('div.language-\\>');

    var makeClipboard = function(elem) {
      var code = elem,
        text = elem.textContent;
        
      if (text.length > 15) {
        if (!clipInit) {
          var text, clip = new ClipboardJS('.copy-to-clipboard', {
            text: function (trigger) {
              var codeElem = prev(trigger).querySelectorAll('code');
              if (codeElem.length > 1) {
                text = prev(trigger).querySelector('code[class^="language-"]').textContent;
              } else {
                text = prev(trigger).querySelector('code').textContent;
              }

              return text.replace(/^\$\s/gm, '');
            }
          });

          var inPre;
          clip.on('success', function (e) {
            e.clearSelection();
            inPre = prop(e.trigger.parentNode, 'tagName') == 'PRE';
            e.trigger.setAttribute('aria-label', 'Copied to clipboard!');
            e.trigger.classList.add('tooltipped');
            e.trigger.classList.add('tooltipped-w');
          });

          clip.on('error', function (e) {
            inPre = prop(e.trigger.parentNode, 'tagName') == 'PRE';
            e.trigger.setAttribute('aria-label', e.action.toString());
            e.trigger.classList.add('tooltipped');
            e.trigger.classList.add('tooltipped-w');
          });

          clipInit = true;
        }

        var notAllowedClass = ['language-mermaid', 'language-viz', 'language-wave', 'language-chart', 'language-msc', 'language-flowchart'];
        var isNotAllowedIncluded = false;
        var curClassName = code.getAttribute('class');

        for (var i = 0; i < notAllowedClass.length; i++) {
          if (curClassName && curClassName.startsWith(notAllowedClass[i])) {
            isNotAllowedIncluded = true;
            break;
          }
        }

        if (!isNotAllowedIncluded) {
          if (curClassName) {
            var newClipboardElem = document.createElement('span');
            newClipboardElem.setAttribute('class', 'copy-to-clipboard');
            newClipboardElem.setAttribute('title', 'Copy to clipboard');
            elem.parentNode.parentNode.insertBefore(newClipboardElem, elem.parentNode.nextElementSibling);
          }
        }
      }
    }

    var makeSymbolClipboard = function(elem) {
      var clipboardSpan = document.createElement('span');
      clipboardSpan.setAttribute('class', 'copy-to-clipboard');
      clipboardSpan.setAttribute('title', 'Copy to clipboard');
      elem.parentNode.parentNode.insertBefore(clipboardSpan, elem.parentNode.nextElementSibling);
    }

    preChromaElem ? 
    preChromaElem.forEach(function(elem) {
      elem.querySelectorAll('code').forEach(function(codeElem) {
        makeClipboard(codeElem);
      });
    }) : null;
    
    langCodeElem ? 
    langCodeElem.forEach(function(elem) {
      elem.querySelectorAll('code').forEach(function (codeElem) {
        makeClipboard(codeElem);
      });
    }) : null;

    dollarCodeElem ? 
    dollarCodeElem.forEach(function(elem) {
      elem.querySelectorAll('code').forEach(function (codeElem) {
        makeSymbolClipboard(codeElem);
      });
    }) : null;

    gtCodeElem ?
    gtCodeElem.forEach(function(elem) {
      elem.querySelectorAll('code').forEach(function (codeElem) {
        makeSymbolClipboard(codeElem);
      });
    }) : null;
    


    
    dollarCodeElem ?
    dollarCodeElem.forEach(function(elem) {
      var lnts = elem.parentNode.parentNode ? elem.parentNode.parentNode.querySelectorAll('.lnt') : null;
      lnts ? 
      lnts.forEach(function(lnt) {
        lnt.innerHTML = '$<br/>';
      }) : null;
    }) : null;

    gtCodeElem ?
    gtCodeElem.forEach(function(elem) {
      var lnts = elem.parentNode.parentNode ? elem.parentNode.parentNode.querySelectorAll('.lnt') : null;
      lnts ? 
      lnts.forEach(function(lnt) {
        lnt.innerHTML = '><br/>';
      }) : null;
    }) : null;
    


    
    
    var lib = JSON.parse("null");

    if (lib && lib.includes('mermaid')) {
      
      var themeVariant = localStorage.getItem('theme') || JSON.parse("\"light\"");

      if (themeVariant === "dark" || themeVariant === "hacker") {
        mermaid.initialize({ theme: 'dark' });
      } else {
        mermaid.initialize({ theme: 'default' });
      }
      
      var mermaids = [];
      [].push.apply(mermaids, document.getElementsByClassName('language-mermaid'));
      mermaids.forEach(function(elem) {
        var elemParentNode = elem.parentNode;

        if (elemParentNode !== document.body) {
          elemParentNode.parentNode.insertBefore(elem, elemParentNode);
          elemParentNode.parentNode.removeChild(elemParentNode);
        }

        var newElemWrapper = document.createElement('div');
        newElemWrapper.classList.add('mermaid');
        newElemWrapper.style.padding = '34px 4px 6px';
        newElemWrapper.innerHTML = elem.innerHTML;
        elem.replaceWith(newElemWrapper);
      });
    }
    
    

    
    if (lib && lib.includes('katex')) {
      var mathElements = document.getElementsByClassName('math');
      var options = {
        delimiters: [
          { left: "$$", right: "$$", display: true },
          { left: "\\[", right: "\\]", display: true },
          { left: "$", right: "$", display: false },
          { left: "\\(", right: "\\)", display: false }
        ],
      };

      renderMathInElement(document.querySelector('.single__contents'), options);
    }
    


    
    if (lib && lib.includes('flowchartjs')) {
      
      var options = JSON.parse("{\"arrow-end\":\"block\",\"element-color\":\"black\",\"fill\":\"white\",\"flowstate\":{\"approved\":{\"fill\":\"#58C4A3\",\"font-size\":12,\"no-text\":\"n/a\",\"yes-text\":\"APPROVED\"},\"current\":{\"fill\":\"yellow\",\"font-color\":\"red\",\"font-weight\":\"bold\"},\"future\":{\"fill\":\"#FFFF99\"},\"invalid\":{\"fill\":\"#444444\"},\"past\":{\"fill\":\"#CCCCCC\",\"font-size\":12},\"rejected\":{\"fill\":\"#C45879\",\"font-size\":12,\"no-text\":\"REJECTED\",\"yes-text\":\"n/a\"},\"request\":{\"fill\":\"blue\"}},\"font-color\":\"black\",\"font-size\":14,\"line-color\":\"black\",\"line-length\":50,\"line-width\":3,\"no-text\":\"no\",\"scale\":1,\"symbols\":{\"end\":{\"class\":\"end-element\"},\"start\":{\"element-color\":\"green\",\"fill\":\"yellow\",\"font-color\":\"red\"}},\"text-margin\":10,\"x\":0,\"y\":0,\"yes-text\":\"yes\"}");
      var jsonContent = null;

      var flowchartPrefix = "language-flowchart";
      var index = 0;
      Array.prototype.forEach.call(document.querySelectorAll("[class^=" + flowchartPrefix + "]"), function(x){
          x.style.display = 'none'
          x.parentNode.style.backgroundColor = "transparent"
          jsonContent = x.innerText;

          var node0 = document.createElement('div');
          node0.id = 'flowchart' + index;
          x.parentNode.insertBefore(node0, x);

          var diagram = flowchart.parse(jsonContent);
          diagram.drawSVG("flowchart"+index, options);

          index +=1;
      });      
    }
    


    
    document.querySelectorAll("mjx-container").forEach(function (x) {
      x.parentElement.classList += 'has-jax'
    });
    


    
    if (lib && lib.includes('msc')) {
      
      var options = JSON.parse("{\"theme\":\"hand\"}");
      var jsonContent = null;

      var index = 0;
      var chartPrefix = "language-msc";
      Array.prototype.forEach.call(document.querySelectorAll("[class^=" + chartPrefix + "]"), function (x) {
        x.style.display = 'none'
        x.parentNode.style.backgroundColor = "transparent"
        jsonContent = x.innerText;
        var node0 = document.createElement('div');
        node0.id = 'msc' + index;
        x.parentNode.insertBefore(node0, x);
        var diagram = Diagram.parse(jsonContent);
        diagram.drawSVG("msc" + index, options);
        index += 1;
      });
    }
    


    
    if (lib && lib.includes('chart')) {
      var borderColor = "#666";
      var bgColor = "#ddd";
      var borderWidth = 2;

      Chart.defaults.global.elements.rectangle.borderWidth = borderWidth;
      Chart.defaults.global.elements.rectangle.borderColor = borderColor;
      Chart.defaults.global.elements.rectangle.backgroundColor = bgColor;

      Chart.defaults.global.elements.line.borderWidth = borderWidth;
      Chart.defaults.global.elements.line.borderColor = borderColor;
      Chart.defaults.global.elements.line.backgroundColor = bgColor;

      Chart.defaults.global.elements.point.borderWidth = borderWidth;
      Chart.defaults.global.elements.point.borderColor = borderColor;
      Chart.defaults.global.elements.point.backgroundColor = bgColor;

      var chartPrefix = "language-chart";
      var index = 0;
      var jsonContent = null;

      Array.prototype.forEach.call(document.querySelectorAll("[class^=" + chartPrefix + "]"), function (x) {
        x.style.display = 'none'
        x.parentNode.style.backgroundColor = "transparent"
        jsonContent = x.innerText;
        var node0 = document.createElement('canvas');
        var source = null;
        node0.height = 200;
        node0.style.height = 200;
        node0.id = 'myChart' + index;
        source = JSON.parse(jsonContent);
        x.parentNode.insertBefore(node0, x);
        var ctx = document.getElementById('myChart' + index).getContext('2d');
        var myChart = new Chart(ctx, source);
        index += 1;
      });            
    }
    


    
    if (lib && lib.includes('wavedrom')) {
      var wavePrefix = "language-wave";
      var index = 0;
      var jsonContent = null;
      
      Array.prototype.forEach.call(document.querySelectorAll("[class^=" + wavePrefix + "]"), function (x) {
        x.style.display = 'none'
        x.parentNode.style.backgroundColor = "transparent"
        jsonContent = x.innerText;
        var node0 = document.createElement('div');
        var source = null;
        node0.id = 'WaveDrom_Display_' + index;
        source = JSON.parse(jsonContent);
        x.parentNode.insertBefore(node0, x);
        WaveDrom.RenderWaveForm(index, source, "WaveDrom_Display_");
        index += 1;
      });
    }
    


    
    if (lib && lib.includes('viz')) {
      var vizPrefix = "language-viz-";
      Array.prototype.forEach.call(document.querySelectorAll("[class^=" + vizPrefix + "]"), function (x) {
        x.style.display = 'none'
        x.parentNode.style.backgroundColor = "transparent"
        var engine;
        x.getAttribute("class").split(" ").forEach(function (cls) {
          if (cls.startsWith(vizPrefix)) {
            engine = cls.substr(vizPrefix.length);
          }
        });
        var viz = new Viz();
        viz.renderSVGElement(x.innerText, { engine: engine })
          .then(function (element) {
            element.style.width = "100%";
            x.parentNode.insertBefore(element, x);
          })
      });
    }
    
    
  }
</script>


            
            <footer class="footer">
    
    
<div class="footer__social">
  <div class="social">
    
            
    
            
    
            
    
            
    
            
    
            
    
      
      <a href="https://github.com/stefanji" title="github" aria-label="github">
        <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 24 24" version="1.1">
<g id="surface3680">
<path fill="currentColor" d="M 10.898438 2.101562 C 6.300781 2.601562 2.601562 6.300781 2.101562 10.800781 C 1.601562 15.5 4.300781 19.699219 8.398438 21.300781 C 8.699219 21.398438 9 21.199219 9 20.800781 L 9 19.199219 C 9 19.199219 8.601562 19.300781 8.101562 19.300781 C 6.699219 19.300781 6.101562 18.101562 6 17.398438 C 5.898438 17 5.699219 16.699219 5.398438 16.398438 C 5.101562 16.300781 5 16.300781 5 16.199219 C 5 16 5.300781 16 5.398438 16 C 6 16 6.5 16.699219 6.699219 17 C 7.199219 17.800781 7.800781 18 8.101562 18 C 8.5 18 8.800781 17.898438 9 17.800781 C 9.101562 17.101562 9.398438 16.398438 10 16 C 7.699219 15.5 6 14.199219 6 12 C 6 10.898438 6.5 9.800781 7.199219 9 C 7.101562 8.800781 7 8.300781 7 7.601562 C 7 7.199219 7 6.601562 7.300781 6 C 7.300781 6 8.699219 6 10.101562 7.300781 C 10.601562 7.101562 11.300781 7 12 7 C 12.699219 7 13.398438 7.101562 14 7.300781 C 15.300781 6 16.800781 6 16.800781 6 C 17 6.601562 17 7.199219 17 7.601562 C 17 8.398438 16.898438 8.800781 16.800781 9 C 17.5 9.800781 18 10.800781 18 12 C 18 14.199219 16.300781 15.5 14 16 C 14.601562 16.5 15 17.398438 15 18.300781 L 15 20.898438 C 15 21.199219 15.300781 21.5 15.699219 21.398438 C 19.398438 19.898438 22 16.300781 22 12.101562 C 22 6.101562 16.898438 1.398438 10.898438 2.101562 Z M 10.898438 2.101562 "/>
</g>
</svg>

      </a>
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
            
    
    
  
  
    
      <a href="https://blog.jiyang.site/posts/index.xml" type="application/rss+xml" title="RSS" aria-label="RSS Feed Link">
        <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><circle fill="currentColor" cx="6.18" cy="17.82" r="2.18"/><path fill="currentColor" d="M5.59 10.23c-.84-.14-1.59.55-1.59 1.4 0 .71.53 1.28 1.23 1.4 2.92.51 5.22 2.82 5.74 5.74.12.7.69 1.23 1.4 1.23.85 0 1.54-.75 1.41-1.59-.68-4.2-3.99-7.51-8.19-8.18zm-.03-5.71C4.73 4.43 4 5.1 4 5.93c0 .73.55 1.33 1.27 1.4 6.01.6 10.79 5.38 11.39 11.39.07.73.67 1.28 1.4 1.28.84 0 1.5-.73 1.42-1.56-.73-7.34-6.57-13.19-13.92-13.92z"/></svg>
      </a>
    
  


  </div>
</div>

    
<div id="gtt">
  <div class="gtt">
    <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M8.12 14.71L12 10.83l3.88 3.88c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41L12.7 8.71c-.39-.39-1.02-.39-1.41 0L6.7 13.3c-.39.39-.39 1.02 0 1.41.39.38 1.03.39 1.42 0z"/></svg>
  </div>
</div>

    <hr />

    <div class="basicflex">
        
    </div>

    <div class="footer__poweredby">
        
                
            <p class="caption">
                
                    ©2020, All Rights Reserved
                
            </p>
        

        
            <p class="caption">Powered by <a href="https://gohugo.io/" target="_blank" rel="noreferrer">Hugo</a> and the <a href="https://github.com/zzossig/hugo-theme-zzo" target="_blank" rel="noreferrer">Zzo theme</a></p>
        
        
    </div> 
</footer>
        </div>
        





<div class="wrapper__right hide" data-pad="true" dir="ltr">
  <script>document.querySelector('.wrapper__right').classList.remove('hide')</script>
  
</div>

    </div>
</body>

</html>